OBIX (Open Building Information Exchange)

oBIX is Niagara’s standards-based door to the outside world. When an enterprise system, analytics platform, or third-party application needs building data over a normal web protocol – not a controls protocol – oBIX is often the cleanest answer. Software Pile builds oBIX integrations in both directions.

oBIX Work We Deliver

  • Exposing Niagara points, histories, and alarms over oBIX for enterprise and analytics consumers
  • Consuming oBIX from other systems into Niagara as typed points
  • Authentication, TLS, and access scoping so an open data door is not an open security hole
  • Payload and watch design that keeps the interface responsive at real point counts

oBIX, REST, or MQTT?

oBIX is not the only way out of a station. Depending on the consumer, a plain REST interface or MQTT may fit better. Part of scoping is choosing the integration that the receiving system actually wants – we will recommend based on the far end, not habit.

Tell us what system needs the data and which direction it flows. We will pick the right interface and scope it.

What Is oBIX?

oBIX — Open Building Information Exchange — is a standard for exposing building system data over web protocols. It presents control-system data as XML over HTTP, so software that knows nothing about BACnet, LonWorks or Niagara can read points, histories and alarms using ordinary web requests.

Its purpose is the boundary between operational technology and IT. Inside the building, control protocols do their job. When an IT system, an analytics platform or a corporate application needs building data, oBIX is one of the standard ways to hand it over without granting access to the control network itself.

When Should You Use oBIX?

It is a good fit when an external system needs building data in a standard, documented form and you would rather not build a bespoke integration per consumer. Typical cases: an energy management platform, a corporate reporting system, a tenant billing application, or a third-party analytics service.

It is a poor fit for high-frequency real-time data, for anything where the consumer already speaks BACnet natively, or where the requirement is really a full application rather than a data feed. A modern REST API or MQTT is often a better answer for new work — oBIX earns its place mainly where a platform specifically requires it.

How Does oBIX Work in Niagara?

Niagara can act as an oBIX server, exposing selected parts of the station, and it can consume oBIX from other systems. The engineering questions are about scope and control rather than plumbing:

  • What is exposed. Publish the points a consumer actually needs, not the whole station. Every exposed point is surface area.
  • Authentication and authorization. Who may read what, enforced by the station.
  • Read versus write. Whether the external system may only observe or may also command — a decision with real consequences that should be made deliberately.
  • Load. An external system polling aggressively can affect station performance; agree rates rather than discovering them.
  • Network position. Where the endpoint is reachable from, and through what. This is a security review, not a configuration step.

oBIX and Security

An oBIX endpoint is a documented way into building data, which makes it worth treating as an exposed interface rather than an internal convenience. Restrict what it publishes, require authentication, prefer read-only where writes are not genuinely needed, keep it off the open internet, and log what accesses it.

The common failure is an endpoint set up for one project, granted broad access to make integration easy, and left in place long after the project ended with nobody owning it. Access review should include it.

Related services: BAS and protocol integration services · custom integration development.

How oBIX Addresses Are Formed

Every oBIX interaction starts at the Lobby object, served at /obix/ on the station. The Lobby is a plain oBIX obj carrying an About record and references to the two things a client needs next: the batch operation and the watch service. Everything else is reached by following href attributes outward from there. There is no separate discovery protocol, no registry, and no directory listing beyond what the objects themselves link to.

Below the Lobby, hrefs track station structure directly. Live data appears under /obix/config/ following the component's slot path, and archived data under /obix/histories/ organized by station name and history name. Because the path is the component path, renaming a folder or moving a point changes the URI a consumer has been storing. That makes the export scope and the URI contract one decision rather than two: a dedicated export folder of proxy points, whose slot names you choose and then freeze, gives the consumer stable addresses and keeps a station reorganization from becoming a client outage.

  • Conformant clients are expected to start at the Lobby and follow links, not hardcode deep paths. In practice most consumers store the deep URI the first time they resolve it, which is what makes a rename expensive later.
  • Slot names are escaped in hrefs using Niagara's dollar-sign hex encoding, so a point displayed as AHU-1 in Workbench addresses as AHU$2d1. A client hand-editing URI strings will get this wrong before it gets anything else wrong.
  • Each obj carries an is attribute naming its contract. That is how a client knows a node is a point, a history, or a watch, rather than inferring type from where it sits in the path.

Watches, Leases, and Poll Cost

Reading every point on a timer is what makes an oBIX interface expensive, and the watch service is the standard answer to it. A client invokes make on the watch service, receives a Watch object with its own href, adds point URIs to it, and then calls pollChanges. pollChanges returns only the members whose values changed since that watch last polled, so a quiet building returns an almost empty response. pollRefresh returns every member's current value regardless of change. Neither is an event stream: a value is reported as it stood when the poll arrived, so a point that moves twice between polls is reported once, and the intermediate value is simply not in the record.

Every watch carries a lease, expressed as a reltime, and each poll resets it. If the client goes quiet for longer than the lease, the station deletes the watch, and the next call against that watch href returns BadUriErr rather than an empty result. A client that treats that as a transport failure and retries the same URI never recovers. Recovery means creating a new watch and re-adding the points, which in turn means the client has to keep its own list of point URIs rather than treating the watch as its only record of what it subscribed to.

Watch problems usually surface as cost or churn rather than as errors, and each has a signature visible in the traffic itself.

  • A client calling pollRefresh every cycle gets correct data and none of the benefit. Response size stays flat no matter how quiet the building is, so if payload does not shrink between polls, that is the call being used.
  • A client that loses its watch and quietly makes a new one each cycle leaves the old ones to expire on their own. Watch counts on the station that climb through the day point at lease expiry, not at point count.
  • Lease length is a negotiation between poll interval and recovery time. A lease shorter than the client's slowest cycle guarantees periodic re-adds, and a very long one means a dead client keeps its subscription alive on the station long after it stopped listening.

History Queries and Where They Break

Each history under /obix/histories/ exposes a query operation that takes a HistoryFilter and returns records as a list, along with the count and the start and end the result actually covers. Left unfiltered, that query returns the whole archive in a single response. What fails first is serialization rather than record count: every record is serialized as an object with a timestamp child and a value child, so a year of 15-minute data is tens of thousands of records and a response measured in megabytes, assembled in station memory before any of it is sent.

Timestamps come back as abstime values carrying an offset, stamped in the station's configured time zone. A consumer that discards the offset and stores local wall time gets a duplicated hour at the fall daylight saving transition and an hour missing in spring, which distorts daily totals long before anyone suspects the interface. Gaps are the other quiet problem: intervals where the point was out of service or the station was down are absent from the result rather than returned as empty records, so an average computed by dividing against an expected sample count is wrong in exactly the periods someone would want to ask about.

  • HistoryFilter fields worth setting on every call: limit, start and end. Paging by explicit time window rather than requesting an open-ended range keeps each response bounded and makes a retry safe to repeat.
  • rollup returns interval aggregates computed on the station rather than raw records, which is the right call whenever the consumer only wants hourly or daily figures.
  • The result reports the range it actually covered. When the end it returns is earlier than the end requested, limit truncated the result, and the next page starts from the returned end rather than from the requested one.
  • Resolution is whatever the history extension recorded. A 15-minute interval extension answers at 15 minutes no matter how fast the underlying point moves, and no filter recovers detail that was never archived.

Batch Requests and the Three Error Types

The Lobby exposes a batch operation that takes a list of items, each naming a URI and whether it is a read, a write or an invoke, and returns a matching list of results. Order is the contract: results are matched positionally, so a client that filters or reorders its request list between building it and sending it will silently attribute values to the wrong points. Nothing in the response labels which request a given result answers.

Batch does not fail as a unit. A request where three of forty URIs are wrong returns HTTP 200 with thirty-seven values and three err objects sitting in the positions where values would have been. A client that checks only the HTTP status will treat those errs as data, and depending on how loosely it parses, as zeros that then average into a report.

The err object's contract says where the problem lives. oBIX defines three, and an interface of any size will meet all of them.

  • BadUriErr means the href did not resolve. It points at a renamed or moved component, or at a slot-name escape the client got wrong. Fetch the parent object and read its children rather than editing the string by hand.
  • PermissionErr means the request authenticated but the user is not permitted on that object. That is Niagara category and role configuration, not oBIX. The signature is a single user reading most of a list and failing on part of it.
  • UnsupportedErr means the object does not implement what was asked, most often a write aimed at a read-only proxy point or an operation invoked on a plain obj. No amount of credential or permission work changes it.

Write Access, Priority, and Release

Whether an external system may write at all is decided by the station rather than by oBIX. The standard leaves identity entirely to the transport, which in practice means HTTP Basic with the credential in a header on every request, and the endpoint rides the station's own web server rather than a listener of its own. Niagara 4 defaults to HTTPS on 443 with plain HTTP disabled. A dedicated station user for the interface, in a role scoped to only the exported category, keeps that credential from being useful anywhere else and makes the access log attributable to a named consumer instead of a shared account.

A write that is accepted has reached the point's priority array at whatever level the interface was configured for. That is not the same as the point moving. Niagara resolves sixteen priority levels and the highest active level wins, so a write at a lower level is accepted, returns cleanly, and changes nothing at the output. Readback returns the resolved output, so the client reads back a value it did not write and cannot explain the difference from the response alone. Which level the external system gets, and what readback should show when it loses, is worth settling before the interface is built.

The standard has no concept of relinquishing. A value written by an oBIX client stays at its level until something else changes it, so a consumer that writes an override and then goes quiet leaves that override in place indefinitely. The release mechanism has to exist in the station: a timer that clears the level after a fixed interval, a higher-priority schedule that reasserts on its own, or an explicit release point the consumer can write to. Which of those applies is a design decision, and it has to be named while the point list is being agreed, because it changes what gets built.

  • Read the point's priority array before escalating a write that appears to do nothing. The level in control is visible there, and it separates an interface fault from station logic doing exactly what it was built to do.
  • A readback that matches what was written is not confirmation that the interface owns the point. It reads identically when something at a higher level happens to be commanding the same value, and diverges only when that other source moves.

Frequently Asked Questions

Does oBIX replace the underlying protocol integration?

No. oBIX never talks to a controller. It publishes what the station has already normalized, so the BACnet, Modbus or LonWorks integration has to exist and be working before oBIX has anything to serve. If a value is not already being polled into a point or written to a history, there is nothing for the endpoint to expose and the work is upstream of the interface.

What has to already exist in the station before an oBIX interface can be turned on?

The data itself. Any point the consumer wants has to be a real point being polled, and any trend it wants has to be a history extension that is configured and has been running long enough to cover the range being requested. Adding a history extension today does not produce last quarter's data. Where the consumer's list includes values nobody was collecting, that is ordinary station engineering and it comes first.

Does the consuming system need anything special to connect over HTTPS?

Usually a certificate decision. A station running its default self-signed platform certificate will not validate against any public trust store, so the consumer has to trust that certificate explicitly, pin it, or the station has to be issued a certificate from an authority the consumer already trusts. A client that has done none of those fails at the TLS handshake, before authentication, which is why the symptom is a connection error rather than a rejected login. Whoever owns the consuming system has to be part of that decision, because the trust store sits on their side.

If we grant write access, can the external system control equipment?

Permission to write and effect on equipment are separate questions. Station user permissions decide whether a write is accepted at all; the priority array decides whether an accepted write reaches the output. A consumer can be fully permitted and still never move a point, and only the permission half of that produces a visible error at the client.

What changes when Niagara is the oBIX client rather than the server?

The far end sets the terms. The station resolves the remote Lobby and creates proxy points against remote hrefs, so whatever naming instability exists on that server becomes yours, and a rename on their side breaks points rather than a report. Watch support on the remote server also decides the update mechanism: if it does not offer one, the station falls back to reading objects on a timer, and the rate is then a load question on their equipment.

What does the receiving system's owner have to decide before the interface can be scoped?

Three things: which values the system needs, named individually; how often it will ask for them; and whether it will ever write. The point list matters more than it sounds because it fixes the URIs the consumer will store and depend on. The rate decides between a watch and a batch read on a timer. Direction matters because a writable interface pulls in the priority and release questions, which a read-only one never raises.