Monorepo containing the Control and Scribe components of the Grovekit IoT stack — a lightweight, self-hosted, opinionated IoT platform built on the Homie MQTT convention, Node.js and TypeScript.
Status: pre-alpha. Production use is highly discouraged.
This repository houses two runtime applications and the shared libraries they depend on:
| Package | Type | Description |
|---|---|---|
@grovekit/control |
App | Server-side-rendered management dashboard for browsing, monitoring, and controlling connected Homie devices. Exposes a live data feed, an alerts view, and a configurable reports system with CSV export. |
@grovekit/scribe |
App | Headless background service that subscribes to MQTT topics via the Homie convention, auto-discovers devices and their properties, and durably persists all datapoints and state changes to TimescaleDB. |
@grovekit/database |
Library | Shared data-access layer built on Kysely and postgres.js. Provides a type-safe query builder, a migration runner, and high-level service functions for devices, feeds, alerts, reports, and time-series datapoints. |
@grovekit/utils |
Library | Shared utilities: runtime configuration from environment variables, structured logging, a batching worker, async helpers, datetime utilities, and typed JSON helpers. |
Scribe connects to the MQTT broker, enables Homie auto-discovery, and durably stores every device state change, property value update, log message, and alert into TimescaleDB. It runs entirely headlessly.
Control connects to both the MQTT broker and TimescaleDB. It serves a server-side-rendered web interface that allows operators to inspect device states, browse time-series charts, configure reports, manage alerts, and issue property set commands directly from the browser.
TimescaleDB stores all relational data (devices, nodes, properties, feeds, reports) and typed time-series hypertables for each Homie datatype (float, integer, boolean, string, enum, JSON).
.
├── docker/ # Docker auxiliary config files
│ └── configs/mosquitto/ # Mosquitto broker configuration
├── packages/
│ ├── apps/
│ │ ├── control/ # @grovekit/control — management dashboard
│ │ └── scribe/ # @grovekit/scribe — data ingestion service
│ └── libs/
│ ├── database/ # @grovekit/database — shared data-access layer
│ └── utils/ # @grovekit/utils — shared utilities
├── docker-compose.yml # Full-stack deployment configuration
├── Dockerfile # Multi-stage build for both apps
├── package.json # Root workspace manifest
├── tsconfig.base.jsonc # Shared TypeScript base configuration
└── tsconfig.build.json # Composite build entry point
- Docker and Docker Compose (v2+)
- A
.envfile at the repository root (copy from.env-example)
# 1. Clone the repository
git clone https://github.com/grovekit/grovekit.git
cd grovekit
# 2. Create and edit your environment file
cp .env-example .env
# 3. Build and start all services in the background
docker compose up --build -d
# 4. Open the Control dashboard at http://localhost:8080
# URL may change dependending on your environment variablesThe stack starts three containers:
| Container | Role | Default exposed port |
|---|---|---|
mosquitto |
MQTT broker | GK_BROKER_BIND_PORT |
timescaledb |
Database | GK_TSCALE_BIND_PORT |
control |
Management dashboard | GK_DASH_BIND_PORT |
scribe |
Data ingestion | (none) |
All variables are read from the environment (or the .env file when running
via Docker Compose).
These control which host address and port each container service is bound to
on the Docker host. They are only used by docker-compose.yml.
| Variable | Default | Description |
|---|---|---|
GK_BROKER_BIND_ADDR |
127.0.0.1 |
Host address to expose the MQTT broker on |
GK_BROKER_BIND_PORT |
1883 |
Host port to expose the MQTT broker on |
GK_TSCALE_BIND_ADDR |
127.0.0.1 |
Host address to expose TimescaleDB on |
GK_TSCALE_BIND_PORT |
5432 |
Host port to expose TimescaleDB on |
GK_DASH_BIND_ADDR |
127.0.0.1 |
Host address to expose the Control dashboard on |
GK_DASH_BIND_PORT |
8080 |
Host port to expose the Control dashboard on |
These are passed into the control and scribe containers (and used directly
when running outside Docker).
| Variable | Default | Description |
|---|---|---|
GK_LOG_LEVEL |
info |
Log verbosity: trace, debug, info, warn, or error |
GK_HOMIE_PREFIX |
homie |
Homie device prefixes for device autodiscovery, separated by commas |
GK_DASH_BIND_ADDR |
localhost |
Address the Control HTTP server listens on inside its container |
GK_DASH_BIND_PORT |
8080 |
Port the Control HTTP server listens on inside its container |
GK_DB_HOSTNAME |
localhost |
TimescaleDB hostname |
GK_DB_PORT |
5432 |
TimescaleDB port |
GK_DB_DATABASE |
grovekit |
Database name |
GK_DB_USERNAME |
(none) | Database username |
GK_DB_PASSWORD |
(none) | Database password |
GK_BROKER_HOSTNAME |
localhost |
MQTT broker hostname |
GK_BROKER_PORT |
1883 |
MQTT broker port |
GK_BROKER_PROTOCOL |
3 |
MQTT protocol version (3 or 5) |
GK_BROKER_CLIENTID |
(none) | MQTT client ID (auto-generated if omitted) |
GK_BROKER_USERNAME |
(none) | MQTT broker username |
GK_BROKER_PASSWORD |
(none) | MQTT broker password |
Pre-requisites:
- Node.js 24 or later
- A running TimescaleDB instance (PostgreSQL 17 + TimescaleDB 2.x)
- A running MQTT broker compatible with the Homie MQTT convention
To install dependencies and build the project:
npm install # Install dependencies
npm run ts:build # Build all packages
npm run ts:watch # Watch mode (incremental rebuild)
npm run ts:clean # Clean build artifactsThis is an npm workspaces monorepo. Each package under packages/ is an
independent workspace that can be built and tested on its own. The root
tsconfig.build.json orchestrates a composite TypeScript build across all
packages in dependency order.