Skip to content

Alarming

Tutorial for creating and managing alerts on time series and meta-data.

Overview

In this article, you will learn how to set up alarms on time series and meta-data on the aedifion.io platform. Currently, the aedifion.io platform supports two types of alarms: i) alarms on the observations for a datapoint and ii) alarms on the throughput (i.e., received observations per time interval) of a certain datapoint or a whole project. You will specify one of each and configure it to send out notifications on alarm events via the Telegram instant messenger or email.

Preliminaries

The examples provided in this article 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 live data ingress.
  • Optionally, a working installation of Python or Curl.

Types of alarms

The aedifion.io platform supports two versatile types of alarms:

  • Threshold alarms are defined on single datapoints and trigger an alarm whenever the measured values for that datapoint exceed (or fall below) a certain threshold. Three severity levels are supported: info, warning, and critical. Each level can optionally have a separate reset threshold to implement hysteresis and prevent flapping. A typical use case for threshold alarms is notifying about unwanted system conditions such as high CO2 concentration in offices.
  • Throughput alarms are defined on single datapoints or whole projects and trigger an alarm whenever the measured throughput for that datapoint or project crosses certain thresholds. Throughput is measured in values per second over a configurable time period. Three severity levels (info, warning, critical) indicate the severity of abnormal throughput. Please contact us to get to know your project's typical data throughput. A typical use case for throughput alarms is fault detection by monitoring of the operational health of the building automation systems, e.g., alerting about the unscheduled shut-down of a critical component or notifying when a sensor is dead.

Further types of alarms will be added in future. If you have a special request, please contact us.

Adding alarms

Threshold and throughput alarms are created through separate endpoints. The parameters that specify the alarm must be encoded as a JSON object and sent in the body of the request.

Adding a threshold alarm

A new threshold alarm is created through the POST /v2/alert/threshold endpoint. The project_id is passed as a query parameter.

Threshold alarms are defined through the following parameters.

Parameter Datatype Type Required Description Example
name string body (JSON) yes The name of the new alarm. Must be unique within the project scope. CO2_Office100
description string body (JSON) no Free text description of the alert. Alert on indoor CO2 level
dataPointID string body (JSON) yes The alphanumeric id of the datapoint on which to send alarms. bacnet100-4120-CO2
thresholds.info float body (JSON) yes The threshold at which the info severity level is triggered. 600
thresholds.info_reset float body (JSON) no The threshold at which the info level is reset. Defaults to the value of info. 500
thresholds.warn float body (JSON) yes The threshold at which the warning severity level is triggered. 1000
thresholds.warn_reset float body (JSON) no The threshold at which the warning level is reset. Defaults to the value of warn. 900
thresholds.crit float body (JSON) yes The threshold at which the critical severity level is triggered. 2500
thresholds.crit_reset float body (JSON) no The threshold at which the critical level is reset. Defaults to the value of crit. 2000
repeat string body (JSON) no Time duration after which to re-send a notification if the alert state has not changed (w = weeks, d = days, h = hours, m = minutes, s = seconds). Defaults to 1h. 2h
notification.email.recipients list of strings body (JSON) no Email addresses to which notifications are sent when the alarm is triggered. ["john.doe@aedifion.com"]
notification.telegram.chat_ids list of strings body (JSON) no Telegram chat IDs where notifications are sent (must be chats that involve @aedifion_bot). ["-219643311"]
notification.dashboard.enabled boolean body (JSON) no Whether to show alerts on the alarm dashboard. Defaults to false. false
attributes object body (JSON) no Key-value tags to assign to the alert for categorization. {"category": "comfort", "team": "Operations"}

Threshold order is automatically determined from the provided threshold values:

  • If info < warn < crit, the order is ascending — the alert gets more critical as values increase.
  • If info > warn > crit, the order is descending — the alert gets more critical as values decrease.

Reset thresholds implement hysteresis. For example, with an ascending alert, a critical alert triggers when observations exceed thresholds.crit and resets only when they fall below thresholds.crit_reset. This prevents the alert from rapidly toggling on and off when values hover around a threshold. If you do not need hysteresis, simply omit the reset values — they will default to the trigger values.

Let's add a threshold alarm on CO2 concentration and see what happens.

from requests import post, get, delete

project_id = 4
api_url = 'https://api3.aedifion.io'
auth_john = ("john.doe@aedifion.com", "mys3cr3tp4ssw0rd")
newalert = {
    "name": "CO2_Office100",
    "description": "Alert on indoor CO2 level with three severity levels.",
    "dataPointID": "bacnet100-4120-CO2",
    "thresholds": {
        "info": 600,
        "info_reset": 500,
        "warn": 1000,
        "warn_reset": 900,
        "crit": 2500,
        "crit_reset": 2000
    },
    "repeat": "2h",
    "notification": {
        "email": {
            "recipients": ["john.doe@aedifion.com"]
        },
        "telegram": {
            "chat_ids": ["-219643311"]
        },
        "dashboard": {
            "enabled": False
        }
    },
    "attributes": {
        "category": "comfort",
        "team": "Operations"
    }
}

r = post(f"{api_url}/v2/alert/threshold",
         auth=auth_john,
         params={"project_id": project_id},
         json=newalert)

print(r.status_code, r.text)
curl "https://api3.aedifion.io/v2/alert/threshold?project_id=4"
    -X POST
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
    -H 'Content-Type: application/json'
    -d '{
          "name": "CO2_Office100",
          "description": "Alert on indoor CO2 level with three severity levels.",
          "dataPointID": "bacnet100-4120-CO2",
          "thresholds": {
              "info": 600,
              "info_reset": 500,
              "warn": 1000,
              "warn_reset": 900,
              "crit": 2500,
              "crit_reset": 2000
          },
          "repeat": "2h",
          "notification": {
              "email": {
                  "recipients": ["john.doe@aedifion.com"]
              },
              "telegram": {
                  "chat_ids": ["-219643311"]
              },
              "dashboard": {
                  "enabled": false
              }
          },
          "attributes": {
              "category": "comfort",
              "team": "Operations"
          }
        }'
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Alert tag, then the POST /v2/alert/threshold endpoint (green).
  4. Enter the project_id in the query parameter field.
  5. Enter the following JSON example in the new_alert body field:
    {
      "name": "CO2_Office100",
      "description": "Alert on indoor CO2 level with three severity levels.",
      "dataPointID": "bacnet100-4120-CO2",
      "thresholds": {
          "info": 600,
          "info_reset": 500,
          "warn": 1000,
          "warn_reset": 900,
          "crit": 2500,
          "crit_reset": 2000
      },
      "repeat": "2h",
      "notification": {
          "email": {
              "recipients": ["john.doe@aedifion.com"]
          },
          "telegram": {
              "chat_ids": ["-219643311"]
          },
          "dashboard": {
              "enabled": false
          }
      },
      "attributes": {
          "category": "comfort",
          "team": "Operations"
      }
    }
    
  6. Click "Try it out!".
  7. Inspect the response body and code.

The JSON-formatted response (HTTP 201) confirms that the alarm was successfully created and returns the details of the alarm:

{
  "id": 6,
  "name": "CO2_Office100",
  "description": "Alert on indoor CO2 level with three severity levels.",
  "alert_type": "threshold",
  "project_id": 4,
  "status": "Enabled",
  "created": "2024-01-15T10:30:00.000000Z",
  "updated": "2024-01-15T10:30:00.000000Z",
  "dataPointID": "bacnet100-4120-CO2",
  "threshold_info": 600,
  "threshold_info_reset": 500,
  "threshold_warn": 1000,
  "threshold_warn_reset": 900,
  "threshold_crit": 2500,
  "threshold_crit_reset": 2000,
  "threshold_order": "asc",
  "period": "2h",
  "email": "john.doe@aedifion.com",
  "telegram_chatid": "-219643311",
  "alarm_dashboard": false,
  "attributes": {"category": "comfort", "team": "Operations"}
}

Note that the alarm has received a unique numeric id (6) and has been enabled immediately. The repeat value you provided during creation is returned as period in the response.

Response format differs from request

The response uses a flat structure while the request uses nested objects. Specifically:

  • thresholds.info, thresholds.warn, thresholds.crit (and their _reset variants) become flat fields threshold_info, threshold_warn, threshold_crit, etc.
  • notification.email.recipients (a list) becomes a single email string with recipients joined by commas.
  • notification.telegram.chat_ids (a list) becomes a single telegram_chatid string with IDs joined by commas.
  • notification.dashboard.enabled becomes alarm_dashboard.

You may already receive alarms or try to provoke some by gathering a few people in your office or by directly breathing into the CO2 sensor. But first, we will add an alarm of the second type, i.e., throughput. Later, we will also look at how to test your alarms by deliberately setting low thresholds.

Adding a throughput alarm

A new throughput alarm is created through the POST /v2/alert/throughput endpoint. The project_id is passed as a query parameter.

Throughput alarms are defined through the following parameters.

Parameter Datatype Type Required Description Example
name string body (JSON) yes The name of the new alarm. Must be unique within the project scope. EON_ERC_Throughput
description string body (JSON) no Free text description of the alert. Alert on project data ingress
dataPointID string body (JSON) no The alphanumeric id of the datapoint on which to measure throughput. If not provided, throughput of the whole project is measured. bacnet100-4120-CO2
thresholds.info float body (JSON) yes First threshold at which throughput is considered slightly abnormal (values per second). 50
thresholds.info_reset float body (JSON) no Threshold at which the info level is reset. Defaults to the value of info. 60
thresholds.warn float body (JSON) yes Second threshold at which throughput is considered significantly abnormal (values per second). 20
thresholds.warn_reset float body (JSON) no Threshold at which the warning level is reset. Defaults to the value of warn. 25
thresholds.crit float body (JSON) yes Third threshold at which throughput is considered critically abnormal (values per second). 0
thresholds.crit_reset float body (JSON) no Threshold at which the critical level is reset. Defaults to the value of crit. 2
period string body (JSON) yes Time period over which to measure throughput (w = weeks, d = days, h = hours, m = minutes, s = seconds). 10m
repeat string body (JSON) no Time duration after which to re-send a notification if the alert state has not changed. Defaults to 1d. 1d
notification.email.recipients list of strings body (JSON) no Email addresses to which notifications are sent. ["john.doe@aedifion.com"]
notification.telegram.chat_ids list of strings body (JSON) no Telegram chat IDs where notifications are sent. ["-219643311"]
notification.dashboard.enabled boolean body (JSON) no Whether to show alerts on the alarm dashboard. Defaults to false. false
attributes object body (JSON) no Key-value tags to assign to the alert. {"category": "network", "team": "IT"}

As with threshold alarms, the threshold order is automatically determined:

  • If info < warn < crit, the alert gets more critical as throughput grows (ascending).
  • If info > warn > crit, the alert gets more critical as throughput drops (descending).
newalert = {
    "name": "EON_ERC_Throughput",
    "description": "Alert on project data ingress throughput.",
    "thresholds": {
        "info": 50,
        "info_reset": 60,
        "warn": 20,
        "warn_reset": 25,
        "crit": 0,
        "crit_reset": 2
    },
    "period": "10m",
    "repeat": "1d",
    "notification": {
        "email": {
            "recipients": ["john.doe@aedifion.com"]
        },
        "telegram": {
            "chat_ids": ["-219643311"]
        }
    }
}

r = post(f"{api_url}/v2/alert/throughput",
         auth=auth_john,
         params={"project_id": project_id},
         json=newalert)

print(r.status_code, r.text)
curl "https://api3.aedifion.io/v2/alert/throughput?project_id=4"
    -X POST
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
    -H 'Content-Type: application/json'
    -d '{
          "name": "EON_ERC_Throughput",
          "description": "Alert on project data ingress throughput.",
          "thresholds": {
              "info": 50,
              "info_reset": 60,
              "warn": 20,
              "warn_reset": 25,
              "crit": 0,
              "crit_reset": 2
          },
          "period": "10m",
          "repeat": "1d",
          "notification": {
              "email": {
                  "recipients": ["john.doe@aedifion.com"]
              },
              "telegram": {
                  "chat_ids": ["-219643311"]
              }
          }
        }'
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Alert tag, then the POST /v2/alert/throughput endpoint (green).
  4. Enter the project_id in the query parameter field.
  5. Enter the following JSON example in the new_alert body field:
    {
      "name": "EON_ERC_Throughput",
      "description": "Alert on project data ingress throughput.",
      "thresholds": {
          "info": 50,
          "info_reset": 60,
          "warn": 20,
          "warn_reset": 25,
          "crit": 0,
          "crit_reset": 2
      },
      "period": "10m",
      "repeat": "1d",
      "notification": {
          "email": {
              "recipients": ["john.doe@aedifion.com"]
          },
          "telegram": {
              "chat_ids": ["-219643311"]
          }
      }
    }
    
  6. Click "Try it out!".
  7. Inspect the response body and code.

The response (HTTP 201) confirms the creation:

{
  "id": 7,
  "name": "EON_ERC_Throughput",
  "description": "Alert on project data ingress throughput.",
  "alert_type": "throughput",
  "project_id": 4,
  "status": "Enabled",
  "created": "2024-01-15T11:00:00.000000Z",
  "updated": "2024-01-15T11:00:00.000000Z",
  "dataPointID": "",
  "threshold_info": 50,
  "threshold_info_reset": 60,
  "threshold_warn": 20,
  "threshold_warn_reset": 25,
  "threshold_crit": 0,
  "threshold_crit_reset": 2,
  "threshold_order": "desc",
  "period": "10m",
  "email": "john.doe@aedifion.com",
  "telegram_chatid": "-219643311",
  "alarm_dashboard": false,
  "attributes": ""
}

Since no dataPointID was provided, the throughput of the whole project is measured.

Response format differs from request

As with threshold alerts, the response uses a flat structure. See the note above for details on how nested request fields map to flat response fields.

Testing your alarms

The previous alarm might have been set too defensively and not trigger unless there is a small party going on in your office. To provoke a threshold alarm and verify it works, you can create an alert with deliberately low thresholds that will trigger immediately, e.g., set "crit": 200 for a CO2 sensor that normally reads above 400 ppm. You may also try to provoke some alerts by gathering a few people in your office or by directly breathing into the CO2 sensor. You will soon see alerts from @aedifion_bot arriving in your Telegram chat (or to your email).

telegram-co2
Figure 1: Telegram alerts on CO2 concentration in action

Similarly, you can provoke a throughput alarm by setting very high thresholds, e.g., "crit": 20000, "warn": 50000 and "info": 100000.

telegram-project
Figure 2: Telegram alert on project throughput in action

Modifying alarms

Note

The API does not support modifying an existing alarm in place. To change an alarm's configuration (e.g., adjust thresholds or notification recipients), delete the existing alarm and create a new one with the updated parameters. See Deleting alarms and Adding alarms.

Enabling and disabling alarms

Since the alarm might now be triggering notifications frequently, let's take a break and disable it. You can disable an alarm to temporarily stop it from sending notifications, and enable it again later. There are two separate endpoints for this: POST /v2/alert/{alert_id}/disable and POST /v2/alert/{alert_id}/enable.

Disabling an alarm

alert_id = 6
r = post(f"{api_url}/v2/alert/{alert_id}/disable",
         auth=auth_john)
print(r.status_code, r.text)
curl "https://api3.aedifion.io/v2/alert/6/disable"
    -X POST
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Alert tag, then the POST /v2/alert/{alert_id}/disable endpoint.
  4. Provide the alert_id.
  5. Click "Try it out!".
  6. Inspect the response body and code.

The response (HTTP 200) returns the alert with its updated status:

{
  "id": 6,
  "name": "CO2_Office100",
  "description": "Alert on indoor CO2 level with three severity levels.",
  "alert_type": "threshold",
  "project_id": 4,
  "status": "Disabled",
  "created": "2024-01-15T10:30:00.000000Z",
  "updated": "2024-01-15T10:35:00.000000Z",
  "dataPointID": "bacnet100-4120-CO2",
  "threshold_info": 600,
  "threshold_info_reset": 500,
  "threshold_warn": 1000,
  "threshold_warn_reset": 900,
  "threshold_crit": 2500,
  "threshold_crit_reset": 2000,
  "threshold_order": "asc",
  "period": "2h",
  "email": "john.doe@aedifion.com",
  "telegram_chatid": "-219643311",
  "alarm_dashboard": false,
  "attributes": {"category": "comfort", "team": "Operations"}
}

Enabling an alarm

To re-enable the alarm, use the enable endpoint:

alert_id = 6
r = post(f"{api_url}/v2/alert/{alert_id}/enable",
         auth=auth_john)
print(r.status_code, r.text)
curl "https://api3.aedifion.io/v2/alert/6/enable"
    -X POST
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Alert tag, then the POST /v2/alert/{alert_id}/enable endpoint.
  4. Provide the alert_id.
  5. Click "Try it out!".
  6. Inspect the response body and code.

The response (HTTP 200) returns the alert with "status": "Enabled".

Listing alarms

You can list all alarms using the GET /v2/project/{project_id}/alerts endpoint. The response is paginated and supports filtering, searching, and sorting.

Parameter Datatype Type Required Description Default
project_id integer path yes The numeric id of the project. —
page integer query no Page number. 1
per_page integer query no Items per page (maximum 100). 20
search string query no Filter alerts by name substring. —
filter string query no Filter by key=value pairs, separated by ;. Keys: alert_type, dataPointID. Filters with the same key are combined with OR, different keys with AND. —
sort_by string query no Sort by field: id, name, or alert_type. id
sort_order string query no Sort order: asc or desc. asc
r = get(f"{api_url}/v2/project/{project_id}/alerts",
        auth=auth_john,
        params={"per_page": 50})
print(r.status_code, r.text)
curl "https://api3.aedifion.io/v2/project/4/alerts?per_page=50"
    -X GET
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Project tag, then the GET /v2/project/{project_id}/alerts endpoint (blue).
  4. Provide the project_id and optionally set pagination/filter parameters.
  5. Click "Try it out!".
  6. Inspect the response body and code.

The response is a paginated object containing a list of alerts and pagination metadata. Among them, we find the alarms we defined previously. Note that the previously disabled alarm has "status": "Disabled" because we paused it earlier.

{
  "items": [
    {
      "id": 6,
      "name": "CO2_Office100",
      "description": "Alert on indoor CO2 level with three severity levels.",
      "alert_type": "threshold",
      "project_id": 4,
      "status": "Disabled",
      "created": "2024-01-15T10:30:00.000000Z",
      "updated": "2024-01-15T10:35:00.000000Z",
      "dataPointID": "bacnet100-4120-CO2",
      "threshold_info": 600,
      "threshold_info_reset": 500,
      "threshold_warn": 1000,
      "threshold_warn_reset": 900,
      "threshold_crit": 2500,
      "threshold_crit_reset": 2000,
      "threshold_order": "asc",
      "period": "2h",
      "email": "john.doe@aedifion.com",
      "telegram_chatid": "-219643311",
      "alarm_dashboard": false,
      "attributes": {"category": "comfort", "team": "Operations"}
    },
    {
      "id": 7,
      "name": "EON_ERC_Throughput",
      "description": "Alert on project data ingress throughput.",
      "alert_type": "throughput",
      "project_id": 4,
      "status": "Enabled",
      "created": "2024-01-15T11:00:00.000000Z",
      "updated": "2024-01-15T11:00:00.000000Z",
      "dataPointID": "",
      "threshold_info": 50,
      "threshold_info_reset": 60,
      "threshold_warn": 20,
      "threshold_warn_reset": 25,
      "threshold_crit": 0,
      "threshold_crit_reset": 2,
      "threshold_order": "desc",
      "period": "10m",
      "email": "john.doe@aedifion.com",
      "telegram_chatid": "-219643311",
      "alarm_dashboard": false,
      "attributes": ""
    }
  ],
  "meta": {
    "total_items": 2,
    "items_per_page": 50,
    "current_page": 1,
    "total_pages": 1
  }
}

Legacy alerts

Alerts created before February 2024 may have different field formats in the listing response:

  • threshold_ok and threshold_dead may be present with actual values.
  • period may be returned as a number (nanoseconds) instead of a duration string.
  • attributes may be returned as a string (e.g. "category=comfort;team=Operations;") instead of an object.

You can also filter results, for example to show only threshold alarms:

r = get(f"{api_url}/v2/project/{project_id}/alerts",
        auth=auth_john,
        params={"filter": "alert_type=threshold"})
print(r.text)
curl "https://api3.aedifion.io/v2/project/4/alerts?filter=alert_type%3Dthreshold"
    -X GET
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd

Deleting alarms

Deleting an alarm is a simple matter of calling DELETE /v2/alert/{alert_id}. The response is HTTP 204 (No Content) with an empty body.

As an example, we now delete the threshold alarm that we have previously created.

alert_id = 6
r = delete(f"{api_url}/v2/alert/{alert_id}",
           auth=auth_john)
print(r.status_code)
curl "https://api3.aedifion.io/v2/alert/6"
    -X DELETE
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api3.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags, select the Alert tag, then the DELETE /v2/alert/{alert_id} endpoint (red).
  4. Provide the alert_id.
  5. Click "Try it out!".
  6. Inspect the response code (204 indicates success).

Go ahead and also delete the throughput alarm, then call GET /v2/project/{project_id}/alerts to verify that both alarms are gone.