This service provides access to both current and past register values of the meter. A register can be thought of as a named column in a database that tracks the value of a measurement over time.
The database consists of rows of register values. Each row has a timestamp indicating the time at which the measurements were taken. The maximum numbers of the rows in the database is fixed and the rows are managed in a round-robin style. Typically, meters can hold up to the most recent 60 years of rows in the database. Older data is automatically dropped.
Older data is stored with a coarser granularity than younger data. A typical database might store the most recent one year of data with 1 minute between rows, the next 9 years with 15 minutes between rows, and the next 50 years with 24-hours between rows. The actual database configuration of a meter can be found in /sys/db.
This most simple use of this service is to fetch the current time
of the meter. This is accomplished with GET /register?reg=none
:
{"ts": "1678475544.123"}
Member ts
returns the time as decimal string. It is a Unix
timestamp that, converted to a
human-readable format, corresponds to March 10, 2023, 19:12:24 and
123ms in the UTC timezone. If the meter is connected to the
Internet, its time should usually be accurate (see
/config/net/ntp and
/config/net/ptp). However, it is advisable
for a client to check the time and confirm its reasonbly close to
actual time as discrepancies could cause confusing and erroneous
results.
Without the reg=none
query parameter, the service also returns
information about the available registers. GET /register
might
return a result looks like this:
{
"ts": "1678475548.000",
"registers": [
{ "name": "V1", "type": "V", "idx": 3, "did": 31 },
{ "name": "grid, "type": "P", "idx": 7, "did": 6 },
{ "name": "temp, "type": "T", "idx": 8, "did": 7 },
{ "name": "mask", "type": "#", "idx": 14, "did": 34 }
]
}
Member registers
contains information about the registers
configured on the meter. The response shows that each register
has a name
, a type
which defines
the physical unit of that register, and several other attributes
which will be explained in more detail later. In our example,
there are registers called V1
, measuring a voltage, grid
measuring power, temp
measuring a temperature, and mask
which records a set of on/off flags.
If we want to find out the current temperature, we can use the
register index given by member idx
of the temp
register to
ask for its current rate. GET /register?reg=8&rate
might
return:
{
"ts": "1678475551.932",
"registers": [
{"name": "temp, "type": "T", "idx": 8, "did": 7, "rate": 13.5629997}
]
}
If we look up type T
in the type code
table, we find that the rate unit is
°C, so the response indicates that the current temperature is
about 13.6 °C or 56.4 °F.
We might also be interested in knowing the average temperature
over the last 24 hours. For that, we need to request the
recorded values for the current time (now
) and 24 hours or
86,400 seconds ago (now-86400
). This can be accomplished
with GET /register?reg=8&time=now,now-86400
:
{
"ts": "1678477555.345",
"registers": {"name": "temp", "type": "T", "idx": 8, "did": 7},
"ranges": [
{ "ts": "1678477555.154", "delta": 1, "rows": [["7494425049"]]},
{ "ts": "1678391100", "delta": 60, "rows": [["7033149079"]]}]
}
The first item returned in the ranges
array is for the current
time, the second for 24 hours ago. Subtracting the two
timestamps, we see that 86,455.154 seconds elapsed between them.
The reason this isn't exactly 86,400 seconds is that the
database records values at a certain granularity and it so
happened that the older row was recorded at a minute boundary.
If we subtract the decimal strings reported in the rows
arrays, we can see that the recorded temperature value increased
from 7,033,149,079 to 7,494,425,049 during that time — an
increase of 461,275,970. That's a big number, but what does it
mean? If we look up type code T
in the type
code table again, we see that the
temperature quantum is 0.001 and the description there also
explains how values are accumulated over time. Thus, if we
multiply the increase in value by the quantum and then divide
by the elapsed time in seconds, we get:
average temp = (461,275,970 · 0.001)°Cs / 86,455.154s = 5.335°C
That is, the average temperature over the past 24 hours was about 5.3 °C or 42 °F.
A Python program illustrating the use of this service can be found
here.
This program takes advantage of class
egauge.webapi.device.Register
to handle the details of encoding
the HTTP requests and decoding the responses. The class also takes
care of:
Converting rates, accumulated and average values to physical quantity objects that have a value and a unit. These objects also can convert to different units, so if you'd like to output energy as british thermal units (Btu) or power as horsepower (hp), you can.
Evaluating virtual registers. The class automatically fetches the formulas of virtual register and then calculates them based on the physical register values as needed.
delta | boolean If present, return the first row of data as usual and each subsequent row as the amount of change since the previous row. This delta-encoding usually reduces the size of the response significantly. With Note that the value of this parameter is ignored and may even be empty. Example: delta=true |
demand | string This parameter may only be specified when output format JSON
(the default) or CSV is selected ( There are two principal methods for subdividing a time period into demand intervals. With the set demand interval method, the longer time period is subdivided into contiguous, non-overlapping demand intervals. For example, with 15 minute demand intervals, an hour would be subdivided into four demand intervals: from minute 0 through 14, 15 through 29, 30 through 44, and, finally 45 through 59. In contrast, with the rolling demand interval method, the larger time period is subdivided into overlapping demand intervals. After each demand calculation, the demand interval is shifted to the right by one minute. With rolling demand, the first demand interval would span minute 46 from the previous hour up to and including minute 0 of the current hour. The next interval would span minute 47 from the previous hour up to minute 1 of the current hour, and so on until the last interval would span minute 45 up to and including minute 59 of the current hour. The value of the
For example, query option When Example: demand=roll|900 |
filename | string For Example: filename=data.csv |
format | string Selects the format of the response. This must be one of:
Example: format=csv |
if | string Only return data if the specified condition is Example: if=epoch==1675276020 |
rate | boolean If present, return the Note that the value of this parameter is ignored and may even be empty. Example: rate=true |
raw | boolean If present, return accumulated values of registers as raw cumulative values which start at zero when the meter database was created. By default, the values are returned relative to the meter epoch, which means register values are zero at the time of the epoch. Note that the value of this parameter is ignored and may even be empty. Example: raw=true |
reg | string Select a range of registers to be included in the result. A range can be one of:
If the value of this parameter starts with a plus sign ( It is also possible to specify combine Virtual registers are output only if they are selected in the
set of registers to be returned and query parameter
Example: reg=all-0:7 |
time | string A comma-separated list of time ranges. Only data for rows that fall within the specified time ranges are returned. Each time-range is processed independently and in the order specified. That is, if overlapping time-ranges are specified, the same rows may be output multiple times. Example: time=now-900:60:now,epoch |
ts | string This query parameter controls how timestamps are handled
during this If non-empty, The Note that the format-string typically will need to be
percent-encoded. In particular, each Example: ts=UTC;%y/%m/%d %I:%M |
view | string Select registers to be included in the result by the view name specified as the value of this parameter. The view name must be prefixed by one of characters:
Example: view==environmentals |
virtual | string This parameter specifies that virtual register should be returned in the response and also selects how to return them. The value of the parameter must be one of:
Example: virtual=formula |
noHTTP | boolean Deprecated If present, requests that the response is to be returned without the normal HTTP headers. Only the body of the response will be returned. Note that the value of this parameter is ignored and may even be empty. |
Register response.
Unauthorized response.
{- "ts": "1678330813.000129799",
- "registers": [
- {
- "name": "use",
- "type": "P",
- "idx": 0,
- "formula": "+\"Grid\"+\"Solar\""
}, - {
- "name": "Grid",
- "type": "P",
- "idx": 17,
- "did": 0,
- "rate": 1798
}, - {
- "name": "Solar",
- "type": "P",
- "idx": 20,
- "did": 1,
- "rate": -4
}
], - "ranges": [
- {
- "ts": "1678298313.000129799",
- "delta": 1,
- "rows": [
- [
- "117607805899",
- "268487638108"
], - [
- "-224",
- "-480"
], - [
- "-218",
- "-481"
]
]
}, - {
- "ts": "1678298040",
- "delta": 60,
- "rows": [
- [
- "905",
- "-3533"
], - [
- "7663",
- "-34573"
], - [
- "12036",
- "-35703"
], - [
- "8418",
- "-36612"
], - [
- "6408",
- "-37505"
]
]
}
]
}