Skip to content
← Work

Building automation · IoT

A building automation platform where a device contract is defined once

A KNX hardware manufacturer needed a software platform to control its own devices and any third-party KNX device. We defined the architecture and built the logic engine, the visual automation editor and the tablet client.

Period
2025 – present
What we delivered
System architecture, logic execution engine, shared type library, admin panel, tablet client
Setting
Two-engineer core team alongside the client

Client and project names are withheld under confidentiality. Sector, scale and outcomes are reported as delivered.

One contract

Node schema shared by backend, admin panel and mobile

4 surfaces

Logic engine, admin panel, API and tablet client

Node graph

Automation composed visually, not hand-written

Android · iOS · web

Single React Native codebase

Context

The client manufactures KNX-based building automation hardware. They needed a software platform to control and monitor its own devices first, and subsequently any third-party device speaking the KNX protocol.

Comparable to Home Assistant in scope, but differentiated by out-of-the-box support for KNX devices, requiring no integration work from the installer. Tablet-first, with mobile and web as follow-on surfaces.

A three-person core team: two senior engineers owning architecture and implementation, plus a designer. We took one of those two seats and owned the overall architecture.

Problem

A platform like this has a structural trap. The definition of a device node — its metadata, its connection handles, its validation rules — is needed by the backend engine that executes it, the admin panel where installers compose it, and the mobile client that displays it. Define it three times and the three definitions drift. Then an installer composes an automation that the engine refuses to execute, and nobody can say which of the three was wrong.

The second constraint: installers are not programmers. Automation logic had to be composable without writing rules by hand.

Approach

One typed contract, consumed identically everywhere

We designed the platform’s shared contract library: a strictly typed TypeScript package defining every node component, its metadata schema, its connection-handle model and runtime validation via TypeBox. It is consumed identically by the backend engine, the admin panel and the mobile client — so a node’s contract is defined exactly once across the entire platform, and a change to it cannot silently fail to reach one of the three.

The logic execution engine

The logic execution engine is the platform’s core: a TypeScript/Fastify service bridging a NATS message bus and Socket.IO clients, routing device events through a graph of composable logic nodes — boolean operators, delay, clock, switch, toggle, dimmer, thermostat, KNX device nodes and VoIP/SIP nodes.

It is built on an abstract node contract, so new node types can be added without modifying the engine. That is the difference between a platform and a product: the engine does not need to know what a thermostat is.

A visual editor instead of hand-written rules

We built the automation editor in the Next.js admin panel on React Flow, letting installers compose logic as a node graph rather than writing rules, with Redux Toolkit and redux-saga managing state and full internationalisation.

The tablet client

The tablet-first control application is built in React Native / Expo, sharing the same typed contracts and communicating with the logic engine over Socket.IO in real time — targeting Android, iOS and web from a single codebase.

SIP/VoIP intercom

We designed and built the intercom subsystem end to end as a proof of concept — the TypeScript/Node backend and the demonstration Android and iOS client applications. Integration points are already present in the logic engine as SipNode and VoipNode; full platform integration remains pending.

Engineering standards

Authored a custom shared ESLint rule package published for the team via semantic-release, plus Jest test suites, strict TypeScript configuration, Prettier, Husky pre-commit hooks and Bitbucket Pipelines CI.

Outcome

  • Delivered across every layer, language and architectural decision in the platform — the TypeScript logic engine and shared libraries, the Next.js admin panel, the dotnet core API and the React Native client.
  • A node’s definition lives in exactly one place. Adding a node type is a change to shared contracts and a new node implementation, not a coordinated edit across three codebases.
  • Installers compose automation visually, with validation derived from the same schema the engine executes against.
  • The engagement continued from a continuous 12-month build into ongoing on-demand work.