Skip to main content
Version: Next

History

Stored tag history is read in three ways: the historian module's own routes (this page), tag.replay over the socket, which asks the historian when it runs and the event backbone otherwise (see Live data over /sync), and the raw backbone window on Runtime and modules. Reports are saved definitions the dashboard runs against the historian. Background in History and replay and Historian.

Historian routes​

All under /api/v1/modules/io.scadex.historian. As module routes, a GET needs viewer and PUT needs engineer. While the module is not running they answer 503 Module unavailable; while its store is still opening in the background they also answer 503, and history reads over the socket come from the backbone meanwhile.

Method and pathRolePurpose
GET /api/v1/modules/io.scadex.historian/statusviewerPosition, lag, oldest and newest sample, size on disk, gaps
GET /api/v1/modules/io.scadex.historian/pointsviewerRaw samples of one tag, oldest first, paged
GET /api/v1/modules/io.scadex.historian/bucketsviewerAggregates per time bucket
GET /api/v1/modules/io.scadex.historian/settingsviewer{"retentionDays": 90}
PUT /api/v1/modules/io.scadex.historian/settingsengineerChange retention

Times on these routes are Unix milliseconds.

Status​

{
"running": true, "retentionDays": 90, "position": 904411, "streamHead": 904411, "lag": 0, "lastBatchAt": "…",
"approximateSamples": 12800411, "tags": 1480, "oldest": 1754900000000, "newest": 1762603200000, "sizeBytes": 734003200,
"gaps": [ { "from": 1760000000000, "to": 1760003600000, "missedMessages": 1200 } ],
"lastPrunedAt": "…", "lastPruneError": null
}

position is the stream position the store has committed; lag is how far behind the live stream it is. gaps are periods the module never received because they expired from the backbone before it caught up.

Raw samples​

GET /api/v1/modules/io.scadex.historian/points?path=Plant.Line1.Temperature&start=&end=&limit=10000&cursor=
ParameterMeaning
pathThe tag's path (a deleted tag stays queryable by its last path until retention removes it; a renamed tag keeps its history)
start, endUnix milliseconds
limit1 to 100000, default 10000 (400 outside the range)
cursorThe previous page's nextCursor; an unparseable cursor is 400

Response:

{ "path": "Plant.Line1.Temperature", "tagId": 17, "start": 1762560000000, "end": 1762603200000,
"points": [ { "…": "one sample per entry: timestamp, value, quality" } ],
"truncated": true, "nextCursor": "…" }

truncated is true when the page filled before end; pass nextCursor back as cursor for the rest. nextCursor is null on the last page.

Buckets​

GET /api/v1/modules/io.scadex.historian/buckets?path=&start=&end=&buckets=500

buckets is 1 to 10000, default 500. Each bucket aggregates the Good numeric values in its span:

{ "path": "…", "tagId": 17, "start": 1762560000000, "end": 1762603200000,
"buckets": [ { "startMs": 1762560000000, "endMs": 1762560086400, "count": 12, "badCount": 0, "min": 71.2, "max": 73.9, "avg": 72.4, "first": 71.5, "last": 73.1 } ] }

min, max, avg, first and last are null for a bucket with no good values; badCount counts the samples that were not good.

Retention​

PUT /api/v1/modules/io.scadex.historian/settings body {"retentionDays": 90}. Shortening it prunes at once; otherwise pruning runs hourly. The data lives in <data>/modules/io.scadex.historian/history.db.

Reports​

Saved report definitions, shared by everyone on the gateway, under /api/v1/reports. Running one is the dashboard asking the historian's bucket route for each tag; there is no server-side run route, and CSV export is done by the dashboard from the fetched buckets. Dashboard side: Reports.

Method and pathRolePurpose
GET /api/v1/reportsviewerEvery report, by name
GET /api/v1/reports/{id}viewerOne report
POST /api/v1/reportsengineerCreate
PUT /api/v1/reports/{id}engineerReplace
DELETE /api/v1/reports/{id}engineerDelete (204)

ReportBody:

FieldTypeRequiredMeaning
namestringyesUp to 80 characters
descriptionstringnoUp to 500 characters
tagPathsstring[]yes1 to 20 paths, each up to 300 characters
windowHoursintegeryes1 to 720
intervalMinutesintegeryes1 to 1440

windowHours * 60 / intervalMinutes must not exceed 2000 rows (400). The response adds id, createdAt and updatedAt (ISO-8601). Unknown ids are 404.