A Comparison of the Brick Schema and Project Haystack

A Systems Approach

Erik Paulson
26 min readApr 6, 2021

Introduction and Motivation

Everyone mostly agrees these days that automated buildings need some standardized semantic metadata about the building to make better use of the data available from a building and the subsystems of the building. People have different names for this — they might call for a “standard tagging library” or a “sound and grounded ontology” or an “extensible schema” or something along those lines, but at the topline, they all mean the same thing: by using common metadata, the meaning of the building’s data can be understood by people and other software applications that weren’t involved in the original creation and collection of the building’s data.

The standards that are most discussed in the world of building management are the Brick Schema (henceforth, ‘Brick’) and Project Haystack (henceforth, ‘Haystack’), and indeed, they both address the problem. Unfortunately, most comparisons of Brick and Haystack are a little unsatisfying, and the reader is usually left wondering “wait, I’m still not quite sure how Brick or Haystack work and how they compare?”

Part of the problem is that the Brick Schema and Project Haystack aren’t really the same sort of thing, and so we get the proverbial “apples to oranges” comparisons. This is usually made worse because the comparisons try to focus only on the semantic markup parts, but don’t ground the examples in the context of an actual end-to-end system. Without seeing how Brick and Haystack plug into an entire system, you don’t get a complete picture of how either Brick or Haystack are used and so you miss out on really understanding the differences between them.

This piece tries to do a comparison of the core of Haystack and Brick, building from a small familiar example. The example doesn’t cover every part of either standard, but it’s enough that you should be able to see how those core ideas would extend to other parts of the standards. No familiarity with either Brick or Haystack is assumed.

We’ll note that the authors of this piece are more familiar with Brick than with Haystack. If there are shortcomings in our description of Haystack it is due to a lack of knowledge of Haystack, despite our best efforts to research the details. We will also note that version 4 of Haystack is under development, but is not yet finalized, so we will stick to Haystack 3 for this piece.

An Example System

To set the stage, we’ll use a small example that is hopefully easy to follow. We’ll have a room with a temperature sensor. The temperature sensor is connected to a programmable controller, which is connected to a fan. We’ll use this as a basic thermostat: when the temperature rises above some value, the controller will turn on the fan. Physically, the setup could look something like this:

A simple room with a temperature sensor, a controller, and a fan
Figure 1:A basic setup

Internally in the controller, we have something like this:

The visual programming language definition for the controller. It is described in the next paragraph.
Figure 2. The control logic, laid out in a visual programming language

This is the program from an EasyIO controller, a popular and well-known line of versatile controllers, but the visual programming/dataflow/wiresheet model of programming should be familiar to most programmers or anyone who configures building automation systems. In this “control program”, the two boxes marked “TempSensor” and “TempSetPoint” feed into the “Cmpr” box where they are compared. If “X is greater than Y”, that is, if “TempSensor” is greater than “TempSetPt”, then the “Cmpr” box tells the “FanControl” object to turn itself on. In this controller, the “TempSensor” object and the “FanControl” object are translated to and from the appropriate electrical signals by the software operating system running on the EasyIO controller.

There are three other boxes in the diagram, all of which start with “BAC”. These are objects that make the values of the program accessible over the network, through the BACnet protocol. These are the “points” of the system, and we have three points: an input point for the temperature sensor, a value point for the setpoint, and an output point for the fan control.

The BACnet protocol is what is known as a “peer to peer” protocol, that is, two devices on the network can simply talk to each other without requiring a server. This is how most printers work on home networks — when you want to add your home printer to your computer, your computer can scan the network and locate the available printer, and if you have more than one computer each computer independently scans the network and locates the printer. Of course, at larger sites like an office the printers are more commonly connected to a server, and to add a printer to your computer you connect to the server and select the appropriate printer. Building controllers work the same way: in small settings there may not be a server, in larger settings there almost certainly is some sort of server. For our example, we’ll include a server, shown in Figure 3, even though it is only connected to a single controller.

Figure 3: The addition of a building automation server

How building controllers are organized into networks is a big topic and there is a lot of variation in approaches. No single approach is “correct” and two buildings might take two different approaches. Note that the “control program” from figure 2 was shown as running on the EasyIO controller in the room, but the same program could be running on the server instead, reading the value from the sensor and sending a network command back down to start the fan. Consider this slightly more complicated environment, in Figure 4:

The same setup as before, but now with a second room with a similar configuration, and the addition of a vent to the original room, though the vent is not present in the second room
Figure 4: Two rooms, with a vent added to the original room

In this figure, there are two rooms, each with a sensor and a controller and a fan. In one of the rooms, there is also a vent that can open to let in outside air. In this setup, the server is used for two purposes. First, it is a single operator workstation that a building manager can look at to see the state of all of the rooms. The controller from each room connects to the server and the server always has the current state of each controller, the operator only has to look at one screen to see both rooms. Second, this server can run additional “control programs” — in this case, imagine a program that opens the vent when the fan starts, and closes the vent when the fan stops.

Again, there’s no single “correct” way to design this setup. The “control program” that runs on the server to open the vent when the fan turns on could run on the EasyIO controller in the room instead of the server, it wouldn’t take much to add that to the program shown in figure 2. Also, it is common at large sites to have multiple levels of servers or controllers. For example, at a campus there may be one main server for the entire campus, and then a smaller server in each building, which helps with scalability and fault tolerance — each building-level server is isolated and can keep running if the server for the campus or another building crashes.

For the rest of this piece, however, we’ll keep to the small example of a controller and a single server, as shown in Figure 3. That’s enough to get us to the first core use case of Brick or Haystack: in order to make sense of the points we can read over the network and interact with them, we need to know the types of the points, and we can do that with standard metadata to describe the points. To go back to the printer example again, applications on our computer don’t need to know the exact details of our printer in order to be able to use it. The operating system can use the metadata it finds from the printer, combined with driver software, and the application can focus on high-level things, like “print this on both sides of the page and with 2 inch margins”, and the metadata and driver can make that happen, no matter if the printer is an HP printer or an Epson printer.

The Metadata for our example

We will start with an examination of the metadata for our example, using both Brick and Haystack. Afterwards, we’ll show how that metadata is used in a system with Haystack or a system with Brick.


We’ll start with Haystack. We have some kind of digital object for each point — think of that however you will, a row in a spreadsheet or a database record are one way to think about them, but it might be easiest to think of each point as an email message in Gmail or a tweet on Twitter or an Instagram post. The key is just to remember that there are three separate digital objects that represent the temperature sensor, the Setpoint, and the Fan on/off signal. They are named, respectively, ‘TempSensor’, ‘TempSetPoint’, and ‘FanControl’ — those were the boxes shown in figure 2.

In both Haystack and Brick, these “digital objects” are called entities, so we will use that as our terminology going forward.

In Haystack, the entities are given “tags”, much like a tweet might have a couple of hashtags in it, or you might have a set of Gmail labels that you put on each message. Tagging goes back a couple of decades, you can read about it on Wikipedia: https://en.wikipedia.org/wiki/Tag_(metadata)

Let’s look at how the temperature sensor might be described using Haystack:

id: @TempSensor
dis: "Temperature Sensor for room 101"
siteRef: @examplebuilding
equipRef: @examplebuilding.room101.fan
kind: "Number"
unit: "°C"

You can see how this is sort of comparable to a tweet — imagine someone had tweeted out

“My name is TempSensor #point #air #temp #sensor”.

Haystack tags are a bit more complicated than Twitter hashtags because they can have values with them — the ‘kind’ and ‘unit’ tags, for example, have two parts, which doesn’t quite match how Twitter handles tags, but it’s mostly the same concept. If twitter supported these “value” hashtags, you could still for the #unit hashtag and get everything, just some would be #unit:°C and some would be #unit:°F

Here’s the key to Haystack: the set of tags that are used are from a standard list. If everyone used their own tags, it wouldn’t be useful — just like with Twitter, the point is to use the same hashtag as others tweeting about the same topic. In Haystack, there’s a standard set of tags to choose from, and that was one of the most important things Haystack provided.

Now, we said that we had three entities, one for TempSensor, one for TempSetpoint, and one for FanControl, but Haystack needs us to add two more. In Haystack, there is always an entity for the ‘site’ and all points need to be linked to some equipment entity. The site entity is tagged with data about the building, there is usually only one site entity per building. There might be multiple equipment entities per site.

The ‘equipRef’ and ‘siteRef’ tags are how Haystack links entities together. In our example, the ‘tempSensor’ point is related to the ‘examplebuilding’ entity, which isn’t really shown in our figures, and to the ‘examplebuilding.room101.fan’ entity — which isn’t quite what’s happening but to fit into Haystack we’ll say the sensor, setpoint, and On/Off control are all part of the “fan” equipment — if we didn’t say that they were part of the fan, we’d have to make up a some kind of “virtual” equipment entity that we might call “low-end-cooling-system” that we just use to group everything together.

We only looked at the temperature sensor, but here’s the entire site. For the most part, the other main entities are similar — TempSetpoint has a ‘sp’ tag instead of a ‘sensor’ tag, and the ‘examplebuilding.room101.fan’ entity has a tag of ‘equip’ rather than a tag of ‘point’.

id: @TempSensor
dis: "Temperature Sensor for room 101"
siteRef: @examplebuilding
equipRef: @examplebuilding.room101.fan
kind: "Number"
unit: "°C"
id: @TempSetpoint
dis: "Temperature Setpoint for room 101"
siteRef: @examplebuilding
equipRef: @examplebuilding.room101.fan
kind: "Number"
unit: "°C"
id: @FanControl
dis: "Control of the fan in room 101"
siteRef: @examplebuilding
equipRef: @examplebuilding.room101.fan
id: @examplebuilding.room101.fan
dis: "The fan in room 101"
siteRef: @examplebuilding
id: @examplebuilding
dis: "White House"
area: 55000ft²
tz: "New_York"
geoAddr: "1600 Pennsylvania Avenue NW, Washington, DC"
geoStreet: "1600 Pennsylvania Ave NW"
geoCity: "Washington D.C."
geoCountry: "US"
geoPostalCode: "20500"
geoCoord: C(38.898, -77.037)

After reading all of that metadata, there is one thing we need to be clear about: humans rarely create Haystack models by writing out text like that. This is the format that Haystack clients and servers send back and forth between each other, humans do not usually need to read or write it. The metadata for each model is usually created in the GUI of the BMS or a Haystack configuration tool, and that tool saves the metadata the machine-readable format above.


Let’s look at our example but using Brick. Brick builds on a data modeling standard called ‘RDF’ — the Resource Description Framework. Here’s an example in the JSON-LD encoding for RDF:

"@id": "http://examplebuilding.com/example#TempSensor",
"@type": [
"https://brickschema.org/schema/1.1/Brick#hasUnit": [
"@id": "http://qudt.org/vocab/unit/DEG_C"

Or, for a more compact representation, there is a ‘terse’ format called “TTL” that we can use to encode the TempSensor entity and might be a little easier to follow

@prefix ex: <example#> .
@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
ex:TempSensor a brick:Air_Temperature_Sensor .
ex:TempSensor brick:hasUnit unit:DEG_C .

It’s really the last two lines here that matter, and in this example, we list two facts about an entity called “TempSensor”: it is of type ‘Air Temperature Sensor”, and it “hasUnit” of degrees celsius. In Brick, the set of types are standardized, like the set of possible tags are standardized in Haystack.

This gets to the first big difference between Brick and Haystack. In Brick, the type or “class” of an entity is explicit, and in Haystack, the type of an entity is determined by which tags are on the entity. Moreover in Brick, the types are defined as a hierarchy of classes — a taxonomy. Brick also defines an ontology that says how these types can interact. Don’t worry too much about taxonomies and ontologies, you don’t need to know them in detail in order to use Brick.

This is the point in any Haystack vs Brick comparison that one points out that the “collection of tags” approach to modeling types for the most part works well but gets into trouble sometimes, especially around subclasses and superclasses. In Brick, the class of an object is explicit, in Haystack, the presence or absence of tags helps determine class specificity: an entity with ‘temp’ and ‘sensor’ as the tags tell us that it’s a temperature sensor, if we add a tag for ‘air’ we know what it is measuring. However, as a counter example, a ‘max air flow setpoint’ is not a more specific version of ‘air flow setpoint’, one is a fixed setting that might be physically impossible to change and the other is a user-configurable value.

We’re not going to go deep into the differences between Brick and Haystack with respect to class hierarchies and tag composition rules. Interested readers can dig into the details in a recent paper from the BuildSys 2019 conference: http://jbkoh.github.io/pdf/buildsys2019_brickplus.pdf or the extended version at https://www.frontiersin.org/articles/10.3389/fbuil.2020.558034/full

Here’s the complete Brick example, adding in the other entities. For this example, we added two other schemas to define our model: we used the “QUDT” schema, which defines the measurement units, and we used the “schema.org” schema, which is the schema that web developers use to give “smart search” capabilities to Google, Yahoo, Bing, and other search engines — by including metadata using the schema.org schema in webpages, Google can give better search results for businesses, like showing the hours a business is located and its address on a map. Because Brick is based on RDF, it is easy to integrate with schemas from other domains.

@prefix ex: <example#> .
@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix schema: <http://schema.org/> .
ex:TempSensor a brick:Air_Temperature_Sensor .
ex:TempSensor brick:hasUnit unit:DEG_C .
ex:TempSetpoint a brick:Room_Air_Temperature_Setpoint .
ex:TempSetpoint brick:hasUnit unit:DEG_C .
ex:FanControl a brick:Start_Stop_Command .ex:Room101_Fan a brick:Fan .
ex:Room101_Fan brick:hasPoint ex:TempSensor .
ex:Room101_Fan brick:hasPoint ex:TempSetpoint .
ex:Room101_Fan brick:hasPoint ex:FanControl .
ex:Room101_Fan brick:isLocatedIn ex:Room_101 .
ex:Room_101 a brick:Room .
ex:Room_101 brick:isPartOf ex:ExampleBuilding .
ex:ExampleBuilding a brick:Building .
ex:ExampleBuilding schema:address ex:ExampleBuildingAddress .
ex:ExampleBuildingAddress a schema:PostalAddress .
ex:ExampleBuildingAddress schema:addressRegion "DC" .
ex:ExampleBuildingAddress schema:postalCode "20500" ;
ex:ExampleBuildingAddress schema:streetAddress "1600 Pennsylvania Ave NW” .

Again, just like the Haystack metadata: humans rarely need to write out RDF/TTL files like the one above. Users configure the points, equipment, and locations of their building in their BMS, and their BMS or Brick configuration utility will save the metadata out in the Brick RDF format. You do not need to know how to write RDF to use Brick.

Where do you get a Brick or Haystack model?

Our motivation for writing this piece was that most comparisons of Brick and Haystack focus only on the differences in the semantics, and don’t cover crucial questions, such as “where does one get a Haystack or Brick model for my building?” The other comparison posts or sample datasets usually have a JSON or CSV-like file for the Haystack example and JSON or a “TTL” file for the Brick example. (“TTL” is pronounced ‘Turtle’ — it’s ‘terse’ format we showed earlier.) But that just punts the question — where did those files come from? We will answer this in three parts: how do we fetch the models to put into these files, how does sensor data fit into this, and how did we create the models in the first place?

Retrieving Data: The Architecture of Brick and Haystack systems


The Haystack specifications, besides defining a set of tags, also define an HTTP-based API to retrieve Haystack models, as well as a set of different data formats for how Haystack data should be returned and stored. Entities can be fetched from a server implementing the Haystack API, and will be returned encoded in a Haystack data format.

The Haystack API includes a query language, though it is somewhat limited. The query language is Haystack-specific but simple enough that it can be understood by any developer very quickly — it’s a set of filters that aren’t that different from an “advanced search” found on the search form of a public library’s book catalog, or a document-focused website, or the search bar of an email application. The filter language of Haystack can be sent as part of the HTTP request and then only matching entities will be returned, for example, “fetch all entities that have the ‘equip’ tag” or “fetch all entities that have the ‘air’ tag AND have an ‘equipRef’ that matches this value.

In most cases, this Haystack HTTP API will be implemented in a server running at the site, usually attached to a traditional building management system server. The Haystack API can be a native capability of the BMS, or potentially added as a plugin, such as the nHaystack server that plugs into Tridium-based BMSes. The Haystack API can be implemented in other places — The GE Current platform (now part of Daintree) uses Haystack as its cloud API for developers to pull data: https://developer.gecurrent.com/intelligent-enterprises/developers-guide You could also implement the Haystack HTTP API on individual controllers, though that is not common.

The Haystack API is specific to Haystack, and not all BMSes implement Haystack. In order to use the Haystack query language, you must have a Haystack server.

Figure 5 is an example of a such a setup, for an on-prem installation. We’ve shown the Haystack server as a separate server from the BAS server, though again sometimes they are combined into one server. The application talks to the Haystack server, and the Haystack server talks to the BMS.

Figure 5. The Application interacts with the Haystack server, using the Haystack API (described below). The Haystack server communicates with the BMS and/or the controllers.

A basic Haystack query would look something like this — it is an HTTP request to http://haystack-server.example.com:

GET /haystack/read?id=@TempSensor
Content-Type: text/plain; charset=utf-8
Accept: text/zinc

And the response from the server would be

HTTP/1.1 200 OK
Content-Type: text/zinc; charset=utf-8
ver: “3.0”
@TempSensor,"Temperature Sensor for room 101",M,@examplebuilding,@examplebuilding.room101.fan,M,M,M,M,"Number","°C"

The Haystack server responds with data encoded into one of the Haystack formats. The default format is called ‘Zinc’, which is close to a CSV but not quite. Using CSV with Haystack isn’t really recommended, and the JSON encoding needs some additional parsing to be useful outside of Haystack. It’s usually better to find a Haystack client library and let it do the parsing.


While Haystack includes a Haystack-specific server in a BMS to implement the Haystack API, Brick models are usually stored in databases that are not specific to Brick. Brick normally uses an “RDF database” and is queried using the “SPARQL” language. RDF and SPARQL are standards managed by the W3C standards body, which also manages the HTML standards, among others.

An RDF database and the SPARQL language are similar to a SQL database, and there are many available. This means that there usually is not a “Brick server” or a “Brick API” built into the BMS, but the Brick model is retrieved from a server that is separate from the BMS, using the standard SPARQL APIs.

The Brick model can be loaded into an RDF database running at the site — example servers include Stardog, Apache Jena, Ontotext GraphDB, or a cloud service such as Amazon Neptune from AWS. The SPARQL standard includes a network protocol to query the database over the network, so support for remote querying is widely available through client libraries in virtually every programming language. The RDF model is used in the so-called “semantic web” and you will occasionally see RDF databases referred to as “semantic web databases” or “semantic web technology”

The Brick RDF model can also be processed without a server. It is common to write a program that loads the Brick model directly from a file and execute a query over the data from the file, without having to load it into a server first. Like remote querying there are software libraries available for virtually every programming language that can query directly over data loaded from a file.

An example SPARQL query might be, just to fetch the data for TempSensor entity

prefix brick: <https://brickschema.org/schema/1.1/Brick#>SELECT ?property, ?value where {
ex:TempSensor ?property ?value .

And the results would be

a   brick:Air_Temperature_Sensor .
brick:hasUnit unit:DEG_C .

Sensor Data in Haystack and Brick

A big difference between Brick and Haystack is how access to sensor data is handled, either historic sensor data or current values. In Brick, the Brick model includes some information on how to retrieve sensor data from other systems. The Brick model can include a pointer to a timeseries historian database along with the ID for the sensor in that timeseries database, or it can use the RDF encoding of the OT network identifiers to provide the address for a sensor, e.g. the Brick model can encode the BACnet object ID that can be used to access the device over BACnet or the Modbus address and register information, or the same for some other protocol. Brick provides a lot of flexibility to locate sensor data and control points but leaves it up to the application to know how to read or write that sensor data or control points through these different protocols. Here’s the temperature sensor example from before, expanded with the metadata necessary to locate this point over BACnet:

@prefix bacnet: <http://data.ashrae.org/bacnet/2020#> .
@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix brickFuture: <https://doesNotExistYet.brickschema.org/Brick#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix ex: <example#> .
ex:device1000 rdf:type bacnet:Device .
ex:device1000 bacnet:device-identifier 1000 .
ex:obj1 rdf:type bacnet:AnalogInputObject ;
bacnet:object-type "analog-input" ;
bacnet:object-name "temp-sensor" ;
bacnet:object-identifier "analog-input,1" ;
bacnet:isPartOf ex:device1000 .
ex:TempSensor a brick:Air_Temperature_Sensor .
ex:TempSensor brick:hasUnit unit:DEG_C .
ex:TempSensor brickFuture:BACnetRepresentation ex:obj1 .

(This example is somewhat future-looking. Brick 1.2 includes the properties for locating historic timeseries databases but does not include a standard property for locating a BACnet object, and the BACnet committee has not yet standardized on an RDF representation for BACnet, but this should be reasonably close to the eventual versions.)

Figure 6 is an example of how such a system would be organized. The application queries the RDF database to find the metadata for the site, and then communicates with the controllers and/or the BAS server to obtain sensor data.

Figure 6. The Application connects to the RDF Graph database to retrieve metadata, and then the application communicates with either the controller or the BAS server to obtain sensor data

Haystack, on the other hand, takes advantage of the fact that Haystack requires a server to query and supports reading (and sometimes writing) sensor and control point data through the Haystack API. In Haystack, points that are tagged ‘his’ can use the HTTP API to fetch historic values for this point, and points tagged with ‘cur’ can use a set of operations through the HTTP API to retrieve the current value and status of the point. (There are some subtleties with retrieving current values in Haystack, see this post for more details: https://project-haystack.org/forum/topic/572 )

The advantage for Haystack is that an application using the Haystack API can be protocol agnostic. The BMS could be using BACnet, or Modbus, or OPC-UA, and it doesn’t matter. The Haystack server is responsible for translating between the Haystack HTTP API and whatever is necessary to read and write that data — though all that complexity is usually already handled by the BMS and so the Haystack API can just use whatever API the BMS provides. On the downside, this means that a Haystack application can only connect to whatever protocols the Haystack server/BMS can use and can’t easily integrate new protocols into the model.

Again, this requires that a Haystack server is part of the stack. Indeed, the Haystack model does not even include enough information to be able to read data unless the request goes through the Haystack server — there is no way to say in Haystack “the history for this sensor is stored in the database located at server db.foo.com.”

For Brick, the model can express virtually anything, but it means applications have to include support for reading from virtually anything. Brick has avoided taking a stronger position on how to read or write data to maintain flexibility, but to borrow a Hamilton lyric, ‘If you stand for nothing, what’ll you fall for?’.

This isn’t to say that some implementations haven’t taken a position. The Brick Github repo includes a sample “Brick Server” that supports returning sensor data in addition to other building metadata like the types of the sensor, and the MortarData Project builds on some of those ideas. Applications do not need to know what the underlying protocol is and can just query the “Brick Server” API. With this option, the architecture looks like the Haystack approach, where the application is oblivious to the communication protocols used by the building, but with the caveat that the BMS or Brick server must implement those protocols.

Figure 7. The Application connects to a “Brick Server”, which either communicates with the BMS or is part of the BMS. The Brick server connects to the RDF database, the application sends its queries to the Brick server, and the Brick server handles communications with the RDF database.

There are also several platforms being developed that use the more developer-friendly GraphQL query language instead of SPARQL to query Brick metadata, and most of these platforms also make sensor data available through that GraphQL API as well. The Microsoft Azure Digital Twins service incorporates Brick into its recommended data model for smart buildings. Azure Digital Twins created its own query language and does not use SPARQL, but it includes a way to read sensor data through the Azure Digital Twins query language and platform.

It is probably a big advantage for Haystack that it has a single API that does both metadata and sensor data, instead of Brick’s default approach of one server for metadata and another server for sensor data. The query language and metadata model that Brick uses is superior to Haystack, and there is more variety of servers available to use with Brick, but being able to get started with one API through Haystack is very compelling. On the other hand, you can use Brick with any setup and any protocol, whereas Haystack requires a Haystack server to be useful, so for systems that don’t have a Haystack server, Haystack is of limited utility.

Creating Haystack and Brick models

So now we’ve seen how to fetch a model, but we still haven’t answered the question, “where does a Brick or Haystack model come from?” And the answer is: usually configured by humans in the BMS, but hopefully that will change in the future to be more automated from other data sources. Recall way back to Figure 2, the wiresheet/dataflow editor. When we were creating the three points in the EasyIO editor and configuring the points, like giving them names and setting their input and output ports, that’s a good place to add some semantic metadata to each entity, like the type of the point.

This “commissioning” work is time-consuming and has been the bane of building automation installers for decades. Good commissioning tools can help make this process faster, and that applies to semantic data configuration as well. Those tools can be smarter UIs, or more automation of being able to bulk-apply operations, or being able to read metadata from end-devices and automatically configure them through a “plug-and-play” setup — there’s been a lot of work and there’s still a lot of work to go. This goes the other way too — good semantic modeling tools can make the commissioning process faster and more accurate.

Because Brick is more flexible and has fewer requirements about what it needs from a server, Brick models are sometimes constructed outside of the BMS, for example by using a BACnet scan and integrating it with data from a BIM. We’ve written more about that here: https://www.linkedin.com/pulse/semantic-data-integration-uniform-meta-data-standards-youngchoon-park/

It’s also usually easy to create a Brick model from a Haystack model. Brick is a superset of Haystack, and anything you can model in Haystack you can model in Brick. There are some cases where there is ambiguity in how the Haystack tags compose together and what the resulting type should be when the Haystack model is converted to Brick, but those can usually be identified and resolved by a human.

With Haystack, if you aren’t configuring the Haystack model directly in the BMS/Haystack server, you have to figure out how to push your configuration back into the BMS.

We’ll just note that commissioning is a challenging problem and one that the industry will be working on for quite a while. However, you should be able to see how the semantic model can be built up from annotating the entities in the BMS, and also see that there are certainly ways to make that faster and less error-prone.

An aside about RFPs

We frequently see building RFPs that say “the building metadata must support a semantic tagging standard such as the Brick Schema or Project Haystack”. Like, literally, that one sentence might be all that the RFP says about it. Don’t get us wrong, it’s a good sign that building owners and facility managers know that they need to care about semantic data and care enough to put it into the RFP! However, as we’ve seen that because of the differences in how a Brick model or a Haystack model is used and queried, it would be good if building owners were a little more specific about what they’re looking for.

If the building owner is just looking for a file with a semantic model of the sensors and equipment of the building, because they’re going to import that file into some other system or they just want a file to have as a canonical reference of how the BMS was configured, then the “either Brick or Haystack” approach is fine for the RFP. The metadata of Brick is a superset of Haystack — everything you can model in a Haystack model you can model in a Brick model.

If the RFP has an application in mind and an application deployment architecture in mind, then the RFP should be more precise about what it is looking for. If the RFP really wants to use the Haystack API, the building owner will be disappointed at handover if the building integrator provides the building owner with a SPARQL endpoint at which to query Brick.

If the building owner creating the RFP simply wants their team of analysts, developers, and integrators to be able to access some kind of semantic data and get access to the sensor data of the building, then either Haystack or Brick is fine to specify in the RFP — but the building owner should be aware, that depending on which vendor wins the bid, the APIs, query languages, and servers used by the building owner and team will be different depending on if Brick or Haystack is used.

The Future

Tagging existed before Haystack, and Haystack did a great service to the building industry by bringing order to the tags used by the people configuring BMSes. Haystack has placed high value on simplicity, even if it means leaving out some capabilities or building its own solution to a problem, such as defining Haystack-only data file formats, and accepting that it means a smaller software ecosystem. The “semantic web” and RDF existed at the time of Haystack’s invention, but the Haystack team chose to stick to the simpler approach with Haystack v1 through Haystack v3.

The “semantic web” has a reputation for being complex. Parts of the underlying ideas of the semantic web trace back to ancient Greece, and anyone who has ever taken a philosophy and logic course in college knows that indeed, things can get complex.

At the same time, most of the complexity of the “semantic web” technology isn’t necessary to use semantic modeling. Millions of webmasters and content managers use semantic web technologies every day: much of the “Search Engine Optimization” technology that makes websites show up properly and be useful in Google and Bing results is all built on semantic modeling, but the webmasters configuring their websites don’t even know they’re using it, they just know how to add the right keywords to their pages. Just like you don’t need to be a mechanical engineer to drive a car, you don’t need to be a software engineer to use semantic modeling. Field technicians and installers can configure equipment, points, and other entities using Brick classes without knowing the first thing about RDF.

The semantic web technology that Brick builds on is logically well-founded. These underlying formalisms aren’t necessary to know in-detail in order to create a Brick model of the points, assets, and locations of a building and the relationships between them, but the formalisms provide reassurance that if new concepts need to be added in the future, there is a clear and correct way to add them. The analogy we like to use is the periodic table. The periodic table was developed before some of the elements were discovered, but chemists could use the periodic table to reason about the properties of those undiscovered elements before they were discovered and understand how they would fit in with what was already known.

Haystack version 4 is moving towards embracing a formal taxonomy and ontology and incorporating it into the next version of the Haystack standard. Haystack has historically built its own data formats — this gives Haystack a format that doesn’t include anything that isn’t necessary — but means that processing Haystack data needs special software. However, Haystack 4 is planning on including a mapping to RDF as well as the Haystack-only data formats. Speaking only for ourselves, we hope that the RDF-Haystack becomes the preferred data format for version 4 users, as it would open up a world of tooling and compatibility for Haystack users.

Haystack 4 is still in development, but a few weeks back in early March of 2021 the Haystack developers proposed a change that will bring Haystack dramatically closer to how Brick works. (See here: https://project-haystack.org/forum/topic/889 ) This change is a really big deal, so much so that the Brick and Haystack teams should have a conversation about what a merged standard and project could look like.

The ASHRAE 223P standard, under development by a working group of the BACnet committee, is also creating a standard for semantic modeling for buildings and the built environment, and is basing the standard on the RDF data model. The ASHRAE semantic model standard will incorporate parts of Brick and parts of Haystack but will be distinct from both of them. The BACnet committee will also clarify/amend the BACnet standard so semantic models can be exchanged over the BACnet protocol. To be clear, neither Brick nor Haystack require BACnet and work fine without BACnet, but systems using Brick/Haystack and BACnet would benefit from BACnet being able to transport semantic data.

The Brick standard is goes beyond HVAC, and incorporates domains such as security and access control, fire protection, location tracking, AV equipment, and eventually perhaps parts of IT. Part of Brick’s mission is to work to facilitate data exchanges between building data sources, and to be the glue that can help exchange data different silos. Brick aims to be expressive enough to be exchange data between the BIM model of a space, the BMS that controls the climate of a space, and the Computer Aided Facility Management (CAFM) that controls the management of the space, without trying to replace all of these systems and their native data formats.


The community is ready to embrace semantic metadata as a foundation of data-driven smart buildings. This will be key to many important use cases, from energy performance and automated fault detection, to presence-aware smart space personalization. The goal of this piece was to provide more of a complete context for both Brick and Haystack. It intentionally left out much of the details of what is actually in the standard tagging library or taxonomy for either standard — those are better covered in the documentation of each standard. Instead, we hope that after having read this piece, you have a better understanding of how each metadata standard is actually used and implemented, and as you read the documentation of each schema, you have a better understanding how it would fit into the full stack of the automation equipment, the BMS, and any applications built on top if it. You should also have a more solid foundation with Brick and Haystack to better understand other comparison articles and blog posts, and be better prepared to follow the standards as they develop and grow.

Further Reading

Bergmann, Harry, Cory Mosiman, Avijit Saha, Selam Haile, William Livingood, Steve Bushby, Gabe Fierro et al. “Semantic Interoperability to Enable Smart, Grid-Interactive Efficient Buildings.” (2020). https://buildings.lbl.gov/publications/semantic-interoperability-enable ( http://dx.doi.org/10.20357/B7S304 )

Fierro, Gabe, Jason Koh, Shreyas Nagare, Xiaolin Zang, Yuvraj Agarwal, Rajesh K. Gupta, and David E. Culler. “Formalizing Tag-Based Metadata With the Brick Ontology.” Frontiers in Built Environment 6 (2020): 152. https://www.frontiersin.org/articles/10.3389/fbuil.2020.558034/full ( https://doi.org/10.3389/fbuil.2020.558034 )

Thanks to Joel Bender for clarifying how BACnet could be represented in Brick. Any errors are the result of the author’s mistranslations from Joel’s advice.



Erik Paulson

Comp Sci Grad student at UW Madison.