Empathic Building server

Warning

The information on this page may be changed without prior notice.

Overview

The Empathic Building system has the following major components:

  • The ReST based back-end (https://eu-api.empathicbuilding.com), running on Azure

  • Sensor gateways, pushing data to the back-end

  • Pusher.com, a third party publish-subscribe service that handles distribution of live updates

  • Web clients, providing the end-user visual interface to the system by loading data from the ReST back-end and subscribing to live updates from Pusher.com

Obtaining access

There are two types of user accounts on the Empathic Building back-end:

  • User accounts

  • Gateway accounts

Third parties wishing to integrate their systems with Empathic Building will need a gateway account. To obtain a gateway account, please request one through EB support at eb.support@haltian.com. You should then receive the following pieces of information:

  1. an access token

  2. an organization ID

  3. a location ID

Authentication

Most endpoints require authentication using the access token obtained from EB support. To authenticate against the service, add the HTTP header authorization: Bearer <token>. For example, if the token you received was fb9ba505321b4fe0a2c9f018c6e3f80a, you need to add the header authorization: Bearer fb9ba505321b4fe0a2c9f018c6e3f80a to your HTTP requests.

Browsing the generated API documentation

Generated API documentation is available at https://eu-api.empathicbuilding.com/doc. Note that invoking the endpoints from the API browser will most likely not work. Instead, a third party tool like Postman is recommended.

Subscribing to live data

To get real time notifications on new, changed or deleted items in the database, you will need a client library for the Pusher.com service. You will then need to configure the client settings appropriately:

  • key: 33d6c4f799c274f7e0bc (production) or 64737761a47148863544 (staging)

  • cluster: eu

You will not need the app_id or secret configuration values. However, you will need to set https://eu-api.empathicbuilding.com/v1/pusher/auth as the authentication endpoint (authEndpoint on the Javascript client) in order to subscribe to the EB channels (which are all private channels). If your selected Pusher client does not have the ability to use an authentication endpoint, you can directly call the authorization endpoint yourself (API docs here), but the details on how to make this work is beyond the scope of this document.

When you have the Pusher client set up, you can subscribe to:

  • Organization channels (private-organization-<ORGANIZATION ID>)

  • Location channels (private-location-<LOCATION ID>)

  • The notifications channel (notifications)

Organization channels receive events with the following topic names:

  • organization-modified (for the organization matching the channel)

  • organization-deleted (for the organization matching the channel)

  • location-created

  • location-modified

  • location-deleted

  • user-created

  • user-modified

  • user-deleted

Location channels, on the other hand, receive events with these topics:

  • asset-created

  • asset-modified

  • asset-deleted

  • gateway-created

  • gateway-modified

  • gateway-deleted

  • sensor-created

  • sensor-modified

  • sensor-deleted

The notifications channel contains the following topics:

  • notification-created

  • notification-modified

  • notification-deleted

Events are gzip compressed, JSON encoded arrays so in order to decode them, you need to follow these steps:

  1. Decode the base64 encoded data into binary

  2. Decompress the binary data using a gzip library

  3. Decode the decompressed (UTF-8 encoded) text using JSON

Each event contains an array of objects:

  • A -created event contains all non-confidential attributes of the newly created object

  • A -modified event contains the ID of the target object and the changes made to its non-confidential attributes

  • A -deleted event contains only the ID of the target object

Sending measurement data

Gateways can send measurement data to the service by posting a JSON encoded array of measurement objects to the add measurements endpoint. Each object must have certain common fields (specified below), plus any extra fields related to the specific measurement type.

When a batch of measurements is received by the server, it is first validated and then sent to a queue for processing. From there, the batch will be picked up by a measurement data processor which will process the measurements using rules specific to the measurement type. If there are no errors, the processed measurements will be appended to the historical data in the database and the sensors’ last communication and last measurement timestamps will be updated along with the last measurement data field. This change will generate a live data event through which the web clients will be informed that a sensor has updated measurement data.

The data processors use the combination of the location_id, vendor, vendor_id and type fields to find matching sensors to update. If no match is found with this combination, a new sensor will be created. Thus, if a sensor is physically moved to a different location, a new sensor instance will be automatically created. The exception to this rule is location data, where location tags are found across all locations within the same organization. This allows users to move between different locations without having to change their associated location tag.

Note

The maximum HTTP request size is 2 MB. Anything larger will result in a 413 error.

Note

Duplicate timestamps are not allowed. Any measurements whose timestamps match previous data will be silently dropped.

Tip

If no new data has been received but a gateway wishes to update the last communication timestamps of sensors, it can send empty sensor status updates for those sensors (with only the mandatory fields filled).

Measurement formats by type

All measurements have certain common fields plus type specific fields.

Timestamps are always represented as milliseconds since the UNIX epoch (1970-01-01 00:00:00 UTC). Percentages are always represented as floating point numbers ranging from 0.0 to 1.0.

The common fields to all measurement types are:

Field

Data type

Unit

Description

type

string

Type of measurement (see below for the full list)

time

integer

ms

Timestamp of measurement

vendor_id

string

Vendor specific sensor ID

name

string

(Optional) Human-readable name of the sensor

Temperature

Measurement type: temperature

Field

Data type

Unit

Description

value

float

°C

Temperature

Humidity

Measurement type: humidity

Field

Data type

Unit

Description

value

float

%

Air humidity (from 0.0 to 1.0)

CO₂ (Carbon Dioxide)

Measurement type: co2

Field

Data type

Unit

Description

value

float

ppm

Amount of CO₂ particles in the air

Air pressure

Measurement type: airpressure

Field

Data type

Unit

Description

value

float

hPa

Air pressure

Occupancy

Measurement type: occupancy

Field

Data type

Unit

Description

used

integer

Number (0 or more) of people (or other things) occupying a space

total

integer

Total number of slots

Noise

Measurement type: noise

Field

Data type

Unit

Description

value

float

dB

Relative loudness of sounds in air

Location

Measurement type: location

Field

Data type

Unit

Description

x

float

m

Horizontal offset from the lower left corner of the floor plan

y

float

m

Vertical offset from the lower left corner of the floor plan

z

float

m

Altitude from the floor

lon

float

°

Longitude

lat

float

°

Latitude

accuracy

float

m

Maximum possible distance between the estimated location and the actual location

floor_id

string

ID of the related floor asset

group

string

One of employee, external, visitor, maintenance, cleaning, asset

Note

Either (x, y) or (lon, lat) are required. The floor_id value is always required. If only (lon, lat) are provided, the target building asset must have the north_vector property set to a valid value in order for the (x, y) values to be filled in.

Reservation

Measurement type: reservation

Field

Data type

Unit

Description

events

array

Array containing the ongoing (if any) and future reservations

Each event in the array has the following structure:

Field

Data type

Unit

Description

start

integer

ms

Start time of the current event

end

integer

ms

End time of the current event

subject

string

Name (usually in the form of “Lastname Firstname”) of the person who made the current reservation (optional)

Satisfaction

Measurement type: satisfaction

Field

Data type

Unit

Description

value

float

%

Satisfaction percentage (from 0.0 to 1.0)

raw_value

integer

Raw survey value from the vendor

Illuminance

Measurement type: illuminance

Field

Data type

Unit

Description

value

float

lux

Illuminance

Distance

Measurement type: distance

Field

Data type

Unit

Description

value

integer

mm

Distance

Stress levels

Measurement type: stress

Field

Data type

Unit

Description

value

float

%

Stress level (from 0.0 to 1.0)

Sensor status updates

Measurement type: sensorstatus

Field

Data type

Unit

Description

battery_voltage

float

V

Battery voltage, if the sensor is battery powered

battery_level

float

%

Battery charge level (from 0.0 to 1.0)

battery_model

string

Battery model name, used to calculate the charge level from the voltage if it is missing (allowed values: cr2032, cr17505)

link_quality

float

%

Link quality (from 0.0 to 1.0)

mesh_neighbors

array[object]

For mesh devices, the list of neighbors seen by the sensor, along with link qualities to them.

mesh_role

string

For mesh devices, the current role of the sensor in the network (sink, headnode, subnode)

mesh_flags

array[string]

For mesh devices, the currently configured flags on the sensor device

mesh_sink_address

string

For mesh devices, vendor ID of the sink device

mesh_next_hop

string

For mesh devices, the vendor ID of the next node on the way to the sink

All fields are optional here.

For the mesh neighbors array, each object has the following structure:

Field

Data type

Unit

Description

vendor_id

string

Vendor ID of a neighboring device

normalized_rssi

float

%

Link quality with the neighbor (from 0.0 to 1.0)

Sensor status updates do not cause new measurements to be inserted, but only updates to the last_status field of a sensor object.

Practical examples (Python)

The following examples have the following requirements:

To subscribe to live sensor data (via modifications of the last_measurement attribute) at location ID 1:

import gzip
import json
from base64 import b64decode
from pprint import pprint
from time import sleep

import requests
from pysher import Pusher

CHANNEL = 'private-location-1'
AUTH_URI = 'https://eu-api.empathicbuilding.com/v1/pusher/auth'
AUTH_HEADERS = {'authorization': 'Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}  # replace this


def print_json(data):
    uncompressed = gzip.decompress(b64decode(data))
    json_data = json.loads(uncompressed)
    pprint(json_data)


def connect_handler(data):
    # Get the authorization token from the EB server
    data = json.loads(data)
    form = {'channel_name': CHANNEL, 'socket_id': data['socket_id']}
    response = requests.post(AUTH_URI, data=form, headers=AUTH_HEADERS)
    response.raise_for_status()
    token = response.json()['auth']

    # Subscribe to the channel
    chan = pusher.subscribe(CHANNEL, auth=token)

    # Add an event handler for "sensor-modified" events
    chan.bind('sensor-modified', print_json)


pusher = Pusher('33d6c4f799c274f7e0bc', cluster='eu', log_level=None)
pusher.connection.bind('pusher:connection_established', connect_handler)
pusher.connect()
while True:
    sleep(1)

To send a new measurement (23.756°C) on behalf of a sensor with vendor ID “ABC-123”:

import requests

AUTH_HEADERS = {'authorization': 'Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}  # replace this


now_milliseconds = int(datetime.now().timestamp() * 1000)
data = [
    {'vendor_id': 'ABC-123', 'time': now_milliseconds, 'type': 'temperature', 'value': 23.756}
]
response = requests.post('https://eu-api.empathicbuilding.com/v2/measurements', json=data,
                         headers=AUTH_HEADERS)
response.raise_for_status()