Desk Occupancy Monitoring Using Temperature Sensors

Tracking desk occupancy can be useful for generating an overview of utilization efficiency. For instance, if only 70% of available desks are utilized in an office environment, the space could be used for other things. Additionally, in environments with free seating, real-time desk occupancy can be used to let people know which desks are available at any given time.

Disruptive Technologies (DT) Wireless Temperature Sensors can be used to detect the presence of people by installing them underneath the desk. By detecting the change in temperature due to body heat radiation, even simple algorithms can provide quite reliable results. In this application note, a simple implementation is showcased to get you started developing your own solution for tracking using our services, with provided code- and data examples.

Figure 1: Four week downwards trend in occupancy during the summer holidays.

Installation Setup

Here are a few notes about how we installed our sensor for gathering desk occupancy.


We chose to use our 2nd generation temperature sensor configured with a 30-second sampling interval for our installation. While a 5.5-minute interval would probably be sufficient, like that provided by the EN12830 sensor, the higher temporal resolution gave more room for experimentation. It is always simpler to down-sample than up-sample data.


Sensors were placed under the desk where a person usually sits. As shown in Figure 2, we found that placing the sensor closer to the edge gave a clearer signal. If any heat source, like a desktop computer, is situated close by, measures should be taken to distance the sensor from said source if possible.

Figure 2: Sensors should be placed beneath the desk where a person sits.

One thing that was considered, but not included in this implementation, is the use of a reference sensor. If placed away from obvious heat sources like air-conditioning or the sun, this could be used to remove the baseline in the desk temperature time series, possibly improving results.


By default, the implementation pulls data from all temperature sensors in the specified project but can be configured to filter on a provided label key. Therefore, using either one of our APIs or DT Studio, ensure that your sensors are all in the same project.


A Service Account must be created and accessible in the target project. Any role will suffice. If you're unfamiliar with this concept, read our Introduction to Service Accounts guide.

Example Code and Data

A repository containing example code and data is hosted on Github. Note that this implementation only aims to get you started with desk occupancy monitoring. It is not meant to be used as a finished product but rather showcases one method of implementing a simple solution.


Running the script with the --sample and --plot-agg optional arguments will estimate occupancy on all provided sample data, then plot the aggregated results.

python3 --sample --plot-agg

The generated plot should look something like the header image.

Pulling Your Own Data

By providing the Service Account credentials set up earlier, the implementation will pull (by default 7 days) data from all sensors in the specified project.

python3 --project_id "<PROJECT_ID>" \
--key_id "<KEY_ID>" \
--secret "<SECRET>" \
--email "<EMAIL>" \
--days 7 \

Additional Configurations

See python3 -h for more optional arguments.

optional arguments:
-h, --help show this help message and exit
--key-id Service Account Key ID
--secret Service Account Secret
--email Service Account Email
--project-id Identifier of project where devices are held.
--label Only fetches sensors with provided label key.
--days Days of event history to fetch.
--sample Use provided sample data.
--plot-desks Plot each individual desk results.
--plot-agg Plot aggregated results

Implementation Details

Changes in temperature caused by a person occupying a desk can be quite significant, up to several degrees Celsius. The change is also quick, which is why we use the temperature Rate of Change (ROC). This results in a lightweight and simple implementation.

Once estimated, the occupancy state of each desk is represented as a binary vector in time. When aggregated hourly and daily, the total occupancy for each period can be represented as shown in the figure below, giving an overview of the usage percentage at a glance.

Figure 3: Three weeks of data for 15 sensors, visualized using the --plot-agg argument.

Typical Occupancy Data

Figure 4 shows 24 hours of temperature data from a sensor mounted beneath a desk. By just examining the data visually, one could point out when it is likely that the desk is occupied with some precision. While each desk is different, a generic implementation should determine the state from this alone.

Figure 4: Typical desk occupancy temperature data.

Calculating Rate of Change

Instead of calculating ROC between each sample pair, x[n]x[n1]x[n] - x[n-1] , we define ROC as the temperature range of a window with a fixed size in time, giving an output as shown in Figure 5.

Figure 5: Temperature Rate of Change for 24 hours of desk occupancy data.

Experimentation showed that this resulted in much more pronounced spikes during occupancy on- and offset. During longer sections where desks were not occupied, the ROC remained stable and did not show any signs of spiking due to typical variations in the ambient air temperature.

Tracking Occupancy State

For each new sample and the related calculated ROC, the logic described by the following pseudo-code snippet determines whether a desk is occupied or not. While it is quite straightforward, it proved to be surprisingly robust to false positives while producing sensible results.

if state was occupied:
if ROC < 0 for more than N seconds:
state not occupied
keep going
if ROC > threshold for more than N seconds:
state occupied
keep going

A constant hard threshold is used for the ROC as changes in the ambient temperature were usually much too slow to cause any significant spiking. Additionally, the time for which the ROC must exceed this threshold for the state to change directly impacts the responsiveness of the implementation.

Figure 6 shows the estimated state for 24 hours of occupancy data. While not perfect, the results seem reasonable when inspected visually. A complex algorithm could probably improve this further.

Figure 6: Temperature data where occupancy is estimated and marked.

Further Development

  • The current implementation is much too simple to differentiate an increase in temperature due to a person occupying the desk from any other heat source. It was, for instance, observed that desks located close to windows would change state if the sun shined directly on it midday.

  • While the current implementation is pretty good at detecting occupancy onsets, determining when people leave their desks may sometimes be too sensitive. This is due to the nature of using pure ROC as a matric, which will go to zero and negative values almost immediately.