Flow Software InfoHub Connector Plugin
The InfoHub Connector re-exposes a Flow Software InfoHub server as an Atlas datasource: Tag history, Measure values per calendar or event period, and event occurrences.
Overview#
The InfoHub Connector re-exposes a Flow Software InfoHub server as an Atlas datasource. One plugin instance connects to a single InfoHub server over HTTPS and publishes, for each operator-defined reference:
- Tags - raw historical values.
- Measures - period values in one of the Measure's calendars (totals, or split by event attribute), or per event period of one of its event schemes.
- Event occurrences - each occurrence of an event scheme with its attribute values.
Measure and event rows carry their attributes, comments, the user who last wrote them, and limit exceptions. Every path supports range reads, Preview and live subscriptions.
Configuration#
Type string: InfoHub


| Option | Type | Default | Required | Description |
|---|---|---|---|---|
| Host | string | - | Yes | Hostname or IP address of the InfoHub server. |
| Port | int | 443 |
No | TCP port the InfoHub REST API listens on. |
| Use TLS | bool | true |
No | Connect over HTTPS (recommended) rather than plain HTTP. |
| ServerKey token | string | - | Yes | Pre-provisioned InfoHub ServerKey JWT, obtained out-of-band from an InfoHub administrator. Attached as-is as an Authorization: Bearer credential on every request; the connector never mints, refreshes, or exchanges this token. |
| References | dict | empty | No | Operator-defined references keyed by operator-chosen name. Each reference identifies a Folder, Metric, or EventScheme by its stable InfoHub id (not by name or path, which are mutable). |
| Default lookback | TimeSpan | 01:00:00 (1 hour) |
No | Read window for a range request that carries no time bounds, and the snapshot window of a Tag subscription. |
| Poll interval | TimeSpan | 00:00:05 (5 seconds) |
No | How often a live Tag subscription polls for newly recorded values. |
| Safety lag | TimeSpan | - | No | How far behind wall-clock a live subscription's watermark trails (asOf = now - SafetyLag). Defaults to twice the poll interval when unset. |
| Period poll interval | TimeSpan | 00:00:30 (30 seconds) |
No | How often a live Measure or event subscription re-reads its revision window. |
| Period revision window | TimeSpan | 1.00:00:00 (1 day) |
No | How far back a live Measure or event subscription watches for new or revised periods. Also its snapshot window. Between 1 minute and 31 days. |
References sub-fields#
Each entry in the References dictionary contains:
| Field | Type | Required | Description |
|---|---|---|---|
| Kind | enum | Yes | The type of InfoHub node this reference roots at: Folder, Metric, or Event. |
| Id | int | Yes | The referenced node's stable InfoHub id (FolderID, MetricID, or EventSchemeID, per Kind). |
Connection setup#
-
Ensure the InfoHub server is running and reachable on the configured Host/Port.
-
Obtain a pre-provisioned ServerKey token from an InfoHub administrator. This is a JWT that grants access to the InfoHub REST API.
-
In the ServerKey token field, paste the obtained token. The connector attaches this as-is in every request; it never exchanges or refreshes the token itself.
-
If the InfoHub server uses a non-standard port other than 443, set Port to that port.
-
If the InfoHub server uses plain HTTP instead of HTTPS, set Use TLS to
false(not recommended). -
In the References dictionary, define one entry per Folder, Metric, or EventScheme you want to publish:
- Key - operator-chosen reference name (e.g.,
"production-metrics"). Used in the catalog binding path. - Kind -
Folder,Metric, orEvent, depending on the type of the referenced node. - Id - the referenced node's stable InfoHub id (never its display name, which can change). Find this in InfoHub's administrative UI.
- Key - operator-chosen reference name (e.g.,
-
Use Test to verify connectivity without going live. The test reports the InfoHub server's reachability and the number of top-level folders visible.
Binding paths#
Each reference advertises one catalog path. Each distinct reference root (Kind and Id) also advertises up to five templates. A template is only advertised where the root has something it can read: a Metric holding only Tags advertises the Tag template alone.
| Path | Reads |
|---|---|
{InstanceId}/{ReferenceKey} |
The catalog: every Tag, Measure and event scheme resolved beneath the reference. |
{InstanceId}/{Kind}/{Id}/[TagId:int] |
A Tag's raw history. |
{InstanceId}/{Kind}/{Id}/[MeasureId:int]/Calendar/[CalendarId:int] |
A Measure's period totals in one of its calendars. |
{InstanceId}/{Kind}/{Id}/[MeasureId:int]/Calendar/[CalendarId:int]/Attributes |
The same Measure and calendar, split by event attribute instead of totalled. |
{InstanceId}/{Kind}/{Id}/[MeasureId:int]/Event/[EventId:int] |
A Measure's value per event period of one of its event schemes. |
{InstanceId}/{Kind}/{Id}/Occurrences/[EventId:int] |
An event scheme's occurrences. |
{InstanceId}is the connector instance id (e.g.,infohub-1).{ReferenceKey}is the dictionary key (e.g.,"production"givesinfohub-1/production).{Kind}and{Id}are the reference's own Kind and Id.- The bracketed placeholders are filled with InfoHub's stable ids. A concrete Measure path looks like
infohub-1/Folder/5/69/Calendar/1.
Catalog paths#
A GetRange request on a catalog path returns an 11-column rowset listing every Tag, Measure and event scheme resolved beneath the reference:
- id (int) - the stable MeasureID, or the stable EventSchemeID on an event scheme row.
- name (string) - the row's name. Empty on an event scheme row when the reference roots at that scheme itself, whose name no browse endpoint supplies.
- unit (string) - the engineering unit, or null.
- intervalType (string) - the interval type (e.g., "Timestamp" for a Tag, "Hourly" for a Measure); null on an event scheme row.
- retrievalType (string) - the retrieval type; null on an event scheme row.
- kind (string) - "Tag", "Measure" or "Event".
- calendars (string) - comma-joined calendar ids the Measure can be read in, or null for a Tag and every event scheme row.
- eventSchemes (string) - comma-joined event scheme ids the Measure can be read in, or null for a Tag and every event scheme row.
- description (string) - the row's description as configured in InfoHub, or null.
- fields (string) - the row's model-attribute fields as a JSON object (e.g.,
{"Area":"Melt"}). Null when the server reported no fields;{}when it reported an empty set. - attributes (string) - an event scheme row's attribute definitions as a JSON array of
{id, name}. These names are exactly the keys that appear in theAttributescolumn of that scheme's occurrence rows. Null on every Tag and Measure row.
The calendars and eventSchemes columns are what fill the CalendarId and EventId placeholders: a Measure can only be read in its own calendars and event schemes.
Using the catalog to drive a mapping#
The catalog is the design-time side of every other path: its rows are metadata about what can be read, not values to subscribe to. Reading it first answers the four questions a mapping needs:
- Which path shape?
intervalTypedecides. "Timestamp" rows are Tags and bind through the Tag path (raw history); every other interval is a period Measure and binds through aCalendarorEventpath. - Which placeholder values? The row's own
id, plus one of itscalendarsoreventSchemesentries. - What should the consumer's property look like?
descriptionandunitbelong in the consuming model's own definition - for an Atlas property, its description and unit annotation in the library. They are copied once, when the property is authored; they do not stream. - What is inside an occurrence's
AttributesJSON? The scheme row'sattributescolumn names the keys before a single occurrence is read.
The catalog path itself can also be bound, like any other path, when the listing is wanted as data - an inventory of what the reference serves. Note that a live subscription's current value keeps only the newest row; range reads return the full listing.
Path resolution example#
With this reference:
"References": {
"production": {
"Kind": "Folder",
"Id": 5
}
}
Suppose the catalog path infohub-1/production lists Tag 100, and Measure 69 with calendars = 1 and eventSchemes = 1. Event scheme 1 sits under Folder 5. You can then bind:
| To read | Bind to |
|---|---|
| Tag 100's raw history | infohub-1/Folder/5/100 |
| Measure 69's hourly totals in calendar 1 | infohub-1/Folder/5/69/Calendar/1 |
| Measure 69 per hour split by Operator, SKU and so on | infohub-1/Folder/5/69/Calendar/1/Attributes |
| Measure 69 per batch of event scheme 1 | infohub-1/Folder/5/69/Event/1 |
| Every batch of event scheme 1 | infohub-1/Folder/5/Occurrences/1 |
An id outside the reference's scope, or a calendar or event scheme the Measure is not associated with, is rejected with an error naming the valid choices. A Measure id on the Tag path is rejected and pointed at the Measure paths.
Reference resolution#
- Metric-rooted references read Tags/Measures directly from that Metric.
- Event-rooted references read Tags/Measures directly from that EventScheme, and offer that scheme's occurrences.
- Folder-rooted references walk the entire subtree: every child folder (recursively), every Metric found along the way, and every EventScheme found along the way. Both branches are included, so neither is silently dropped. The walk stops at 5000 nodes with a warning.
Rowsets#
Tag history#
- Timestamp (datetime) - the recorded time.
- Value (double, nullable) - the measured value, or null if InfoHub recorded no value.
- Quality (int) - the OPC-DA quality byte (192 = Good, 64 = Uncertain, 0 = Bad).
Measure periods#
All three Measure paths return the same columns:
| Column | Type | Description |
|---|---|---|
| Timestamp | datetime | Period start. |
| PeriodEnd | datetime, nullable | Period end. Null for an event period that is still open. |
| Duration | double, nullable | Period length in milliseconds. |
| Value | double, nullable | The Measure's value for the period. |
| Quality | int | OPC-DA quality byte. |
| PeriodId | long | The calendar period, or the event occurrence, the value belongs to. On the Event path this is the occurrence's own id, so it joins to the Occurrences path. |
| ValueId | long | The value's own id, unique per attribute split and per version. |
| Pending | bool | The period is still being calculated. |
| Preferred | bool | Only preferred values are read, so always true. |
| Version | int | Revision number. A recalculated or edited value arrives as a new ValueId with a higher Version on the same PeriodId. |
| RecordedAt | datetime, nullable | When the value was written. |
| Formatted | string, nullable | The value as InfoHub displays it. |
| Attributes | string (JSON), nullable | Attribute values, e.g. {"Operator":"E. Lopez","SKU":"BNL-MT-12-01"}. On the /Attributes path each row carries exactly one. |
| Comments | string (JSON), nullable | [{"text":"...","at":"...","user":{...}}] |
| User | string (JSON), nullable | The user who last wrote the value: {"username":"...","email":"...","name":"..."} |
| Limits | string (JSON), nullable | Limit exceptions with the limits evaluated against: [{"high":300,"target":150,"highException":true,"lowException":false}] |
Event occurrences#
| Column | Type | Description |
|---|---|---|
| Timestamp | datetime | Occurrence start. |
| PeriodEnd | datetime, nullable | Occurrence end, or null while it is still open. |
| Duration | double, nullable | Length in milliseconds, up to now for an open occurrence. |
| PeriodId | long | The occurrence id. |
| Index | long, nullable | The occurrence's sequence number within its scheme. |
| QualityStart, QualityEnd | int, nullable | Quality of the start and end triggers. |
| Preferred, Version | bool, int | As for Measure periods. |
| Attributes, Comments, User | string (JSON), nullable | As for Measure periods. |
Attribute values are trimmed: InfoHub returns some, such as Work Order, padded with trailing spaces. Every column is always present, so a path's columns never change between reads.
Totals or attribute splits#
InfoHub keeps two sets of numbers for a Measure in a calendar: the period total, and the value split by event attribute ("scrap this hour while SKU was X"). They are different datasets, not the same rows with extra columns, so they are separate paths:
.../Calendar/[CalendarId:int]- one row per period: the total..../Calendar/[CalendarId:int]/Attributes- one row per period per attribute value. The same attribute can appear more than once in a period when it held the same value in two separate stretches, so key such rows on ValueId.
On the Event path every row already carries all of the event period's attribute values.
Range reads#
The read window comes from the request's Timestamp bounds. When a side is missing, Default lookback fills it (no bounds at all: the lookback ending now). Which periods come back follows InfoHub's own rules:
- Calendar paths return periods lying wholly inside the window, plus the one that straddles the window's start, reported as starting at the window's start. A period straddling the window's end is not returned, and the current calendar period never is: InfoHub writes a calendar value only once the period has closed.
- Event and Occurrences paths return every event period overlapping the window, including one still open.
A transient read failure returns an empty rowset. A range too large to read in full (more than about five million periods) fails with an error instead, because an empty rowset would read as "no data in that range". Narrow the range.
Quality column#
This plugin emits a Quality column (OPC-DA integer) for Tag and Measure rowsets. The URI is atlas-common:Quality, type xsd:integer. Values:
- 192 - Good (normal data)
- 64 - Uncertain (e.g., out of range, last-known, or below instrument precision)
- 0 - Bad (e.g., device offline, sensor error)
The quality value comes directly from InfoHub and is passed through without remapping.
Live subscriptions#
Every template path supports live subscriptions. Catalog paths do not.
Tag paths#
- A snapshot is fetched over the configured Default lookback window, ending at (now - SafetyLag).
- Every Poll interval, the plugin queries the InfoHub server for values recorded since the last poll and emits them as updates.
- On silence (a poll tick with no new values), a bare watermark advance is emitted so downstream calculated properties do not stall.
Measure and Occurrences paths#
A period changes after it is first written: it stays pending until it closes, a recalculation or manual edit bumps its version, comments and limit exceptions are added later, and an open event period gains its end. So these subscriptions work differently:
- The snapshot covers the Period revision window (or Default lookback, if longer), up to now.
- Every Period poll interval, the plugin re-reads the whole revision window and emits only the rows that are new or have changed since they were last sent.
- The watermark advances every tick, as on Tag paths.
Period rows arrive with a Timestamp earlier than the watermark already sent, because a calendar period is only written once it has closed and a revision can touch any period in the window. Atlas uses the last row of each update as the property's live value, so every update ends with the newest period: a revision of an older period never rolls the live value back. On the /Attributes path that last row is one split of the newest period, so the path suits range reads better than a live property.
Every tick re-reads the whole revision window. An hourly calendar over the default one day is 24 periods per tick; a one-minute calendar over 31 days is around 45,000, which is dozens of requests every tick for each subscription. Set Period revision window to how far back revisions realistically happen.
Subscription errors#
On a poll failure, the connector applies bounded backoff (1 second, then 5 seconds, then 30 seconds) and retries. After three consecutive failures, the subscription is faulted and torn down; Atlas will re-route it if the path is still subscribed.
A change to the connection settings faults every subscription so they reconnect. Editing references faults only the subscriptions whose path no longer resolves: the Measure left the reference, lost that calendar or event scheme, or the event scheme is no longer beneath it.
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| Connection refused / timeout | Host/Port wrong, InfoHub server not running, firewall blocking, or TLS mode mismatch. | Verify Host and Port match the InfoHub server's actual address. Check that Use TLS is set correctly (true for HTTPS, false for HTTP). Confirm the firewall allows the port. Use Test to verify connectivity. |
| Authentication failure (403) | ServerKey token invalid, expired, or absent. | Verify the ServerKey token is the exact JWT provided by the InfoHub administrator. Confirm it has not expired. Re-fetch a new token from the administrator if needed. |
| Catalog path returns empty | Reference kind/id is wrong, or nothing is beneath it. | Verify the reference Kind and Id in the InfoHub server's administrative UI. Confirm at least one Tag or Measure exists under that Folder/Metric/EventScheme. |
| Template path returns no rows | Id out of scope for the reference, or the time range is outside stored history. | Verify the id is among those the catalog path returns. For reads without explicit time bounds, adjust Default lookback to cover the data you expect. |
| "has no calendar" or "has no event scheme" error | The calendar or event scheme in the path is not one the Measure is associated with. | Use an id from the Measure's calendars or eventSchemes column in the catalog. The error lists the valid ones. |
| "is a Measure, which has no raw history" error | A Measure id was used on the Tag path. | Bind to one of the Measure paths instead (.../Calendar/... or .../Event/...). |
| Calendar path never shows the current hour, shift or day | InfoHub writes a calendar period's value only once the period has closed. | Expected. The period appears once InfoHub has calculated it. For a running value, use the Event path if the Measure has an event scheme. |
| Calendar path returns totals but the attribute values are missing | The totals path carries no attributes; the split values are a separate dataset. | Bind to .../Calendar/[CalendarId:int]/Attributes. |
| "too large" error on a Measure or event read | The range holds more periods than one read will fetch (about five million). | Narrow the time range. |
| Live subscription opens but emits nothing | No values in the snapshot window, or SafetyLag is too large. | Check the InfoHub server's data in the window. For Tag paths, reduce SafetyLag or increase Default lookback; for Measure and event paths, increase Period revision window. Check connector logs for poll failures. |
Use the Test button in Connect's admin UI to probe the InfoHub server without opening a live subscription. The test reports the reachable Host/Port and the number of accessible top-level folders.