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
andend_time
must be RFC3309 timestamps. In the example below, the Z indicates the timestamp is in UTC.- You can retrieve up to 90 days 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.