# room-assistant: room-level presence for home automation

> room-assistant is a NestJS service that tracks which room of your house people are in, using Bluetooth and thermopile sensors, and exposes that presence to a home automation suite. The interesting part is the sensor side, because a thermal sensor can see a person on a sofa where a motion sensor cannot.

**mKeRix/room-assistant** — Presence tracking and more for automation on the room-level

- Repository: https://github.com/mKeRix/room-assistant
- Website: https://www.room-assistant.io
- Stars: 1,357 · Forks: 124
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/mkerix-room-assistant

## Knowing who is in which room

room-assistant brings your home automation onto the next level, which the project calls room automation. It tracks room occupancy and your location around the house with what it describes as great accuracy, plus any other sensors you may want to attach.

The examples in the README make the value concrete. You can turn lights and heating on only in the rooms where people are actually there. You can accurately know if someone is there even when you are just chilling on your couch, which is a situation where a motion sensor would fail and leave you in the dark. And you can go a step further and configure your personal thermostat preferences or turn on your favourite TV channels depending on who is in the room.

That couch example is the whole argument for the project, and it is also the technical claim that needs scrutiny. A motion sensor is a cheap binary signal, and it fails in exactly the case that matters most for heating and lighting, which is a person who is present but still. A thermopile sensor measures infrared radiation, so it registers a warm body that is not moving. A Bluetooth signal from a phone or a wearable is a different mechanism again, and it tracks a specific person rather than a room.

The last point in the introduction is the integration model. You pick and choose the parts you need from the flexible software to get the data you need for writing new automations, and it integrates with the home automation suite you already use. The repository topics name Home Assistant and hassio alongside presence-detection, sensors, bluetooth, thermopile and home-automation, and the package keywords say the same: smart home, home automation, home assistant, presence, bluetooth, thermopile.

## A NestJS service with a config file as the extension point

The package manifest shows what this is under the hood, and the stack is a conventional NestJS application on version 8 of the framework, with @nestjs/common, core, platform-express, platform-ws, schedule, swagger and terminus among the dependencies.

The entry points are the two that a TypeScript project needs. The main field points at dist/src/main.js and the types at dist/src/main.d.ts, and there is a bin entry at ./bin/room-assistant.js, which is the command line wrapper the Docker image symlinks into /usr/local/bin. The scripts are the standard Nest set: build is nest build, start is nest start, start:dev watches, start:prod runs node dist/main, and the lint, format and test scripts use eslint, prettier and jest with a coverage variant.

The interesting design decision is in the files list. Alongside the compiled code, the published package includes dist/config/definitions/*.yml, and the repository has a config/ directory at the top level. That tells you the integrations are not code in TypeScript but YAML definitions, which is how the pick-and-choose model in the introduction is implemented. An integration is a configuration entry, not a module you have to compile.

The rest of the tree is the usual NestJS layout: src/ for the source, typings/ for the type declarations, nest-cli.json for the Nest CLI configuration, docs/ for the documentation sources, bin/ for the wrapper, and the .run/ directory for the IDE run configurations.

The API surface is also conventional, since @nestjs/swagger is in the dependency list, and @nestjs/terminus is there for the health endpoints that the container's health check calls.

## The container, and the capabilities it needs

The Dockerfile is where the hardware requirements become visible, and it is worth reading carefully because the list of packages is the list of things this service has to talk to.

The build stage starts from node:16-alpine3.12 and installs python3, make and a C++ toolchain, plus libusb-dev, eudev-dev, avahi-dev, cairo-dev, jpeg-dev, pango-dev and giflib-dev. Those last four are the graphics stack, which is there for whatever the service renders, and the USB and eudev packages are for talking to hardware that is not Bluetooth. The stage then installs the published package from npm with a version argument.

The runtime stage is the same base image with a longer package list: bluez and bluez-deprecated for the Bluetooth stack, libusb, avahi-dev for the mDNS discovery, bind-tools, dmidecode, tini as the init process, curl and tzdata, and the same graphics libraries. The two winston transports for Loki and Elasticsearch are installed globally as well, so the logs can be shipped to a log store without a second configuration file.

The part that will make you pause is the capability grants. The image sets cap_net_raw on the node binary and on hcitool, and cap_net_admin on hciconfig. Those are the capabilities needed to use raw Bluetooth sockets and to configure the adapter, and they are also the reason the container runs as tini and room-assistant with the digResolver command by default.

The health check is a curl against the status endpoint on port 6415, with a 15 second start period, which tells you the service needs a moment before it answers.

## Development with Compose, and the host network mode

The development compose file is short, and one line in it has consequences.

```yaml
services:
  room-assistant:
    build:
      context: .
      dockerfile: dev.Dockerfile
    network_mode: host
```

The service is built from the dev.Dockerfile rather than the production one, and it runs with network_mode: host instead of a bridge network. That is not a stylistic choice. Bluetooth and the mDNS discovery this service depends on do not behave well inside a container's own network namespace, and host networking is the pragmatic way to let the container see the host's radios and the local network. The cost is that the container's ports are the host's ports, and there is no network isolation between the two.

The configuration is passed as a JSON blob in the NODE_CONFIG environment variable, and the compose file shows the shape it takes, with a global object holding the instance name and the integrations list:

```yaml
environment:
  NODE_CONFIG: >
    {
      "global": {
        "instanceName": "dev-instance",
        "integrations": []
      }
    }
```

That single block shows the shape of the whole configuration model. The integrations array is where the sensors go, and it is empty in the development file, which is why the flexible pick-and-choose model in the introduction is a configuration decision rather than a code change.

The other development pieces are the dev.Dockerfile at the root for a container with the sources mounted, the .devcontainer/ directory for a development container, and the .vscode/ and .run/ directories for editor and IDE run configurations.

## Docs, API and the site

Documentation is split between a hosted site and a documentation source tree in the repository, and both are part of the project.

The site is room-assistant.io, with an installation guide and a configuration guide linked from the README, and the repository has a docs/ directory that is built with VuePress, since the scripts include docs:dev as vuepress dev docs and docs:build as vuepress build docs. So the documentation site is generated from the same tree, which is why the guides can be versioned alongside the code.

The API documentation is generated from the code rather than written by hand, since @nestjs/swagger is a dependency, and @nestjs/terminus provides the health and status endpoints that the container health check calls.

For anyone integrating this with a home automation suite, the configuration guide is the document that matters, because the integrations are YAML definitions and the options for each one live there.

The repository also has the standard supporting files for a project with a long history: a codecov.yml and the coverage badge, a .husky/ directory with the git hooks, a .commitlintrc.json, a .prettierrc, an .eslintrc.js, a .editorconfig, a .dockerignore and the GitHub workflows. The semantic-release badge in the README is how versions are cut, and the funding link in the manifest points at GitHub Sponsors.

## The release history and the gap in it

The maintenance picture is unusual, and it is the thing to weigh before you adopt.

The last push to the repository was on 2026-10-13, and the repository is not archived. The tagged releases, however, stop in March 2022. v2.20.0 was tagged on 2022-03-20, and v3.0.0-beta.5 was tagged the same day, with v3.0.0-beta.4 before that on 2021-09-23. The version in the package manifest is 2.20.0, matching the newest stable tag.

So the tree is being worked on while the published packages are four years old, and the 3.0 line never left beta. There is a reasonable reading in which the project moved to a different distribution channel, since the Docker image installs the package from npm with a version argument and the compose file builds from source, but the README does not explain it, and the honest statement is that the release tags and the repository history have diverged.

The dependency set points the same way. The NestJS dependencies are at version 8, the Docker base image is node:16-alpine3.12, and the winston transport versions are not pinned in what is visible. None of that is fatal, but a project that has not cut a release in four years and still builds on Node 16 will need work before it runs on a current base image.

What has not changed is the idea. Room-level presence is still a gap in most home automation setups, and a service that exposes it through a simple configuration file, with the sensor integrations kept out of the code, is still a reasonable thing to run on a LAN you control.

## Conclusion

Adopt room-assistant if you want presence per room rather than per house, if you have a sensor setup that can see stationary people, and if you are prepared to run a service with elevated network capabilities on your LAN. Do not adopt it expecting a maintained package, because the newest stable release was v2.20.0 on 2022-03-20 while the tree has continued to receive pushes, so pin a version and read what changed. Before you start, check whether your automation suite can consume the presence states at all, since integration is the point of the project, and review the container's capability grants, because the image adds raw socket and network admin capabilities to Node and the Bluetooth tools to reach the radios.

## FAQ

### What does room-assistant do?

It is a home automation service that tracks room occupancy and your location around the house, plus any other sensors you attach, and it feeds that into the home automation suite you already use. The pitch is lighting and heating only where people actually are, including where someone is present but still on a sofa.

### How are integrations configured in room-assistant?

As YAML definitions rather than compiled modules. The published package ships the definitions under dist/config/definitions, and the configuration is passed through the NODE_CONFIG environment variable with a global section holding the instance name and an integrations list, so you pick and choose the parts you need without touching the source.

### What does the room-assistant Docker image need?

The runtime stage of the image installs bluez, libusb, avahi-dev, bind-tools, dmidecode, tini and curl, and it grants cap_net_raw to node and hcitool and cap_net_admin to hciconfig so the service can use raw Bluetooth sockets and configure the adapter. The health check polls the status endpoint on port 6415.

### Is room-assistant still maintained?

The repository is not archived and the last push was on 2026-10-13, but the tagged releases stop in March 2022 with v2.20.0 and v3.0.0-beta.5, and the 3.0 line never left beta. The dependencies are NestJS 8 and a node:16-alpine3.12 base image, so expect work before running it on a current stack.

### How do I install room-assistant?

The project points to its own documentation site, room-assistant.io, for the installation and configuration guides, and the package is published on npm as room-assistant. The Docker image is built from the repository, and the development compose file builds from dev.Dockerfile with network_mode: host so the container can reach the host's Bluetooth radios and the local network.

## Sources

- [License: MIT](https://github.com/mKeRix/room-assistant/blob/main/LICENSE)
- [mKeRix/room-assistant on GitHub](https://github.com/mKeRix/room-assistant)
- [Project website](https://www.room-assistant.io)
- [README](https://github.com/mKeRix/room-assistant/blob/main/README.md)
- [Releases](https://github.com/mKeRix/room-assistant/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mkerix-room-assistant
