Skip to main content

Retrieving Telemetry Data

This tutorial guides you through retrieving telemetry data associated with your sites via the Voltus API.

Telemetry at Voltus

Voltus collects and retains energy usage data for a variety of reasons, including:

  • Compliance
  • Monitoring and improving performance during grid dispatches
  • Optimizing market strategy to maximize revenue

We offer a number of integration options for sending energy usage data to Voltus. Your Account Manager works with you to determine the best option for your business.

Energy usage data is visible on the VoltApp Real-Time Energy Dashboard and available through an API endpoint. This tutorial will discuss how to retrieve it using the latter method.

Requirements

  • A Voltus API key (VOLTUS_API_KEY). If you don’t have one, email api-support@voltus.co or your Account Manager.
  • One or more sites that have stored telemetry data.

Getting Site IDs

You can skip this step if you already have a set of IDs you want telemetry data for.

Otherwise, retrieve a list of your sites through the get /sites endpoint. The following cURL request will do this for you:

curl -- header 'X-Voltus-API-Key: YOUR_API_KEY' https://api.voltus.co/2022-04-15/sites

The response will look something like this:

{
"sites": [
{
"name": "site 1",
"id": "as7f",
"customer_location_id": "your_id_1",
"meters": [
{
"id": "rtas",
"name": "meter for site 1"
}
]
},
{
"name": "site 2",
"id": "k829",
"customer_location_id": "you_id_2",
"meters": [
{
"id": "1k38",
"name": "meter for site 2"
},
{
"id": "8j3j",
"name": "generator meter for site 2"
}
]
}
],
"page": 0,
"perPage": 0
}

You should save the IDs of the sites, not the meters.

Making the request

You can retrieve telemetry data by making a GET request to https://api.voltus.co/2022-04-15/telemetry/kw. Several things to note:

  • If you are requesting data for multiple sites, add multiple site_id parameters in the path. Using multiple site IDs is more efficient than making multiple requests. (See example below)
  • start_time and end_time must be RFC3309 timestamps. In the example below, the Z indicates the timestamp is in UTC.
  • You can only retrieve 48 hours worth of telemetry data in a single request. The API reference contains all parameter details.

The following cURL request will retrieve data for sites as7f and k829 between 12:00:00 (exclusive) and 12:01:00 (inclusive) UTC (indicated by the Z) on the 8th of June, 2023. You can change the dates and IDs to your use-case.

curl --header "X-Voltus-API-Key: YOUR_API_KEY" "https://api.voltus.co/2022-04-15/telemetry/kw?start_time=2023-06-08T00:00:00Z&end_time=2023-06-08T00:01:00Z&site_id=as7f&site_id=k829"

Here would be the response:

{
"data": {
"sites": [
{
"site_id": "as7f",
"meters": [
{
"meter_id": "d761",
"telemetry": [
{
"interval_seconds": 30,
"timestamp": "2023-06-08T00:00:30Z",
"value": 608.72,
"units": "kw"
},
{
"interval_seconds": 30,
"timestamp": "2023-06-08T00:01:00Z",
"value": 608.46,
"units": "kw"
}
]
}]
},
{
"site_id": "as7f",
"meters": {
{
"meter_id": "74lo",
"telemetry": [
{
"interval_seconds": 30,
"timestamp": "2023-11-14T00:00:30Z",
"value": -1189.44,
"units": "kw"
},
{
"interval_seconds": 30,
"timestamp": "2023-11-14T00:01:00Z",
"value": -1196.16,
"units": "kw"
}
]
}
}
}
]
}
}

Interpreting the Results

Each telemetry object represents a reading across some interval of time. The interval ends at timestamp and has a length of interval_seconds.

{
"interval_seconds": 30,
"timestamp": "2023-06-08T00:00:30Z",
"value": 608.72,
"units": "kw"
}

This reading indicates that from 00:00:00 to 00:00:30, this meter reported a consumption rate of 608.72 kw, for a total energy consumption of approximately 5 kwH.

We did not receive data points with timestamp 12:00:00 Even though start_time was 12:00:00. This is because start_time is exclusive. If we wanted to retrieve the data point for 12:00:00, we could set start_time to ‘2023-06-08T11:59:59Z’.

Negative values

If the meter represents a generator, the values will be negative when it is producing electricity. The value represents the amount of energy that is being consumed.

  • Site asf7 has a generator. Its meter values are negative because it is producing electricity.

Latency

Data freshness is normalized to 30 second intervals. Polling every 30 seconds will fetch the most up-to-date telemetry. However, polling less frequently can also be appropriate, depending on your needs.

Retrieving Telemetry Data and Storing the Results

While you can read the output of the previous cURL requests, it’s not in a structure that’s particularly useful for investigation or analysis. This section contains a code snippet that will retrieve telemetry data for a single site and store it in a CSV file.

This source code to this script can also be found in voltus-api-examples as telemetry/get_readings.py

import os
import sys
import csv
import requests
import urllib
from datetime import datetime, timedelta

MAX_REQUEST_SIZE_HOURS = 48
SECONDS_IN_HOUR = 3600.0
VOLTUS_API_URL = os.getenv("VOLTUS_API_URL", "https://api.voltus.co")
VOLTUS_API_KEY = os.getenv("VOLTUS_API_KEY")

s = requests.Session()
s.headers.update({"X-Voltus-API-Key": VOLTUS_API_KEY, "Accept": "application/json"})


def _get_telemetry(site_id: str, start_time: datetime, end_time: datetime):
"""
returns a list of telemetry readings, each one being represented as a dictionary with the following fields:
{
"site_id": "aSiteID",
"meter_id": "aMeterID",
"interval_seconds": 30,
"timestamp": "1970-01-01T00:00:00Z",
"value": 10,
"units": "kw"
}
"""
if start_time > end_time:
raise Exception("end time cannot be before start time")

readings = [] # will contain all telemetry readings

current_start = start_time
while current_start != end_time:
# compute end_time for request in this loop
current_end = end_time
interval = end_time - current_start
if interval.total_seconds() / SECONDS_IN_HOUR > MAX_REQUEST_SIZE_HOURS:
current_end = current_start + timedelta(hours=MAX_REQUEST_SIZE_HOURS)

# make request
path_params = {
"start_time": current_start.replace(microsecond=0).isoformat() + "Z",
"end_time": current_end.replace(microsecond=0).isoformat() + "Z",
"site_id": site_id,
"interval_seconds": 30,
}

url = urllib.parse.urljoin(VOLTUS_API_URL, "/2022-04-15/telemetry/kw")
resp = s.get(url, params=path_params)
resp.raise_for_status() # raise an exception if request fails

json = resp.json()

for site in json["data"]["sites"]:
site_id = site["site_id"]
for meter in site["meters"]:
meter_id = meter["meter_id"]
for reading in meter["telemetry"]:
reading["site_id"] = site_id
reading["meter_id"] = meter_id
readings.append(reading)

# setup next iteration
current_start = current_end

return readings


if __name__ == "__main__":
if len(sys.argv) != 2:
sys.stderr.write(f"USAGE: {os.path.basename(sys.argv[0])} <site id>\n")
sys.exit(1)
if VOLTUS_API_KEY is None:
sys.stderr.write("VOLTUS_API_KEY environment variable is unset")
sys.exit(1)

start_time = datetime.utcnow() - timedelta(days=8)
end_time = datetime.utcnow() - timedelta(days=1)
site_id = sys.argv[1]

readings = _get_telemetry(site_id, start_time, end_time)

# write readings to csv
with open("readings.csv", "w") as csvfile:
fieldnames = [
"site_id",
"meter_id",
"interval_seconds",
"timestamp",
"value",
"units",
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for reading in readings:
writer.writerow(reading)

Copy the contents of this into a file on your local machine and name it get_telemetry.py. The script expects the environment variable VOLTUS_API_KEY to contain your application key. It also expects a site_id as its first and only argument.

To run this script you'll need to set the VOLTUS_API_KEY environment variable. On Linux or MacOS:

export VOLTUS_API_KEY="YOUR_API_KEY_HERE"

Or in Windows Powershell:

$Env:VOLTUS_API_KEY="YOUR_API_KEY_HERE"

Once the environment variable is set you can invoke the following command with a site ID you own:

python get_telemetry.py your_site_id

Note: this assumes you are executing the command from the same directory the script is in.

The script will generate a file named readings.csv in the directory the script ran in that contains one row per telemetry reading. Subsequent runs of the script will override previous data.