Official starter template for building an external integration for
Gladys Assistant with the JavaScript SDK
@gladysassistant/integration-sdk.
Fork it, add the GitHub topic
gladys-assistant-integration, push a multi-arch image, bump the version — that's publishing. No account, no review.
This is not a 40-line hello-world: it deliberately shows several device
types so you can copy the one closest to your hardware. Everything lives in
the src/devices/ folder (one file per device type), and every
place where you would talk to your real hardware / cloud API is marked with a
DO THE WORK comment and a logger call.
| Device | Type illustrated | SDK hooks used |
|---|---|---|
| Weather station | Read-only sensors (temperature + humidity), real data via Open-Meteo | onPoll, publishStates, onAction |
| Living room switch | Binary actuator (ON/OFF) | onSetValue, publishState |
| Living room light | Dimmable light (on/off + brightness) | onSetValue per feature |
| Office plug | Mixed: actuator + power metering, cloud/local transport badge | onSetValue, onPoll, publishTransports |
| Entrance motion sensor | Push / event-driven sensor | startPush, publishState |
| Entrance camera | Camera images: periodic snapshot + on-demand fresh capture | publishCameraImage, onGetImage |
The wiring (connection, auth, reconnection, dispatch) is in
index.js — you rarely need to touch it.
.
├─ index.js # SDK bootstrap + event wiring (no device logic)
├─ src/
│ ├─ devices/ # ← one file per device type (edit these)
│ │ ├─ index.js # registry: list your devices here
│ │ ├─ weatherStation.js # read-only sensors (poll)
│ │ ├─ switchDevice.js # binary actuator
│ │ ├─ light.js # dimmable light (on/off + brightness)
│ │ ├─ plug.js # actuator + power metering + transport badge
│ │ ├─ motionSensor.js # push / event-driven sensor
│ │ └─ camera.js # camera images (push + pull)
│ ├─ weather.js # example real "driver" (Open-Meteo)
│ └─ config.js # config defaults + normalization
├─ gladys-assistant-integration.json # manifest (name, config schema, image…)
├─ Dockerfile # Node 24 Alpine, read-only rootfs ready
├─ .github/workflows/release.yml # UI-driven release: bump + tag + build
├─ .github/workflows/build.yml # multi-arch build (git tag or called by release)
└─ cover.png # catalog cover, 800×534 px, ≤150 KB
To add a device type, create a new file in src/devices/ following the same
shape as the existing ones, then register it in src/devices/index.js. Business
logic (the device modules) and utilities (weather.js, config.js) are kept
separate so the parts you edit stay small.
The plumbing you would otherwise copy into every integration comes straight from the SDK (v0.5.0+):
logger/createLogger({ name })— leveled console logger (LOG_LEVELenv var), with named/child loggers per module. Since SDK v0.4 the SDK also logs its own connection lifecycle (under thegladys-sdkname), so connectivity problems show up indocker logswithout extra code;DEVICE_FEATURE_CATEGORIES,DEVICE_FEATURE_TYPES,DEVICE_FEATURE_UNITS— the standard Gladys categories / types / units, no manual string copying;gladys.externalIds(type, platformId)— builds the unique, stable device and feature external ids;gladys.handleShutdown(cleanup)— graceful SIGTERM/SIGINT handling;gladys.setConnectionStatus(connected, message?)— application-level connection status shown in the Configuration screen (the template reports it after every (re)initialization);gladys.onAction(key, cb)— handler of a manifestactionsbutton: the template declares atest_weatheraction (manifestactionsfield) and the weather station blueprint implements it, returning the multi-language message displayed under the button;gladys.publishCameraImage(externalId, image)/gladys.onGetImage(cb)(SDK v0.5) — the camera image channel: push a periodic snapshot and answer on-demand capture requests with animage/jpg;base64,...string (≤ 150 KB, max 12 images/minute per device). Dedicated channel: images never go through the states history. Seesrc/devices/camera.js;gladys.publishTransports(entries)+DEVICE_TRANSPORTS(SDK v0.5) — the per-device cloud/local transport badge for dual-channel devices. The manifest declares"transports": ["local", "cloud"], so the Configuration screen shows a standard "Prefer the local connection" toggle whose value arrives as the reserved, read-only config keyGLADYS_PREFER_LOCAL(boolean, defaulttrue). The demo plug applies the preference and reports its effective transport. Seesrc/devices/plug.js.
The SDK offers more for integrations that need it — OAuth2 cloud flows
(onOAuthAuthorizeUrl / onOAuthCallback + an oauth2 config field),
sub-containers (getContainers, startContainer… + the manifest containers
field) and mediated network discovery (scanNetwork + the manifest
network_discovery field, for UDP-broadcast / mDNS / SSDP scans from the
core). See the
SDK README for those
patterns; this template stays focused on devices.
npm install
GLADYS_HOST_API_URL="http://localhost:1443" \
GLADYS_INTEGRATION_TOKEN="<token>" \
GLADYS_INTEGRATION_SELECTOR="demo-devices-template" \
LOG_LEVEL=debug \
npm startThe three GLADYS_* variables are injected by the Gladys supervisor when the
integration runs inside its sandboxed container. The SDK reads them
automatically.
The template ships with the tooling every integration should keep. The same
three checks run automatically on every push and pull request (see
.github/workflows/ci.yml):
npm run format:check # Prettier: is everything formatted?
npm run format # Prettier: format everything in place
npm run lint # ESLint: catch real mistakes (unused vars, dead code…)
npm test # Unit tests, via the built-in `node --test` runnerTests live in test/ and use Node's native test runner — no extra
test framework to install. Add a *.test.js file next to the ones already
there and it is picked up automatically.
Before you tag a release, you can check that your integration passes the store validation locally, without waiting for the hourly indexer. Run the store's validator against your integration directory:
npx github:GladysAssistant/integration-store .It runs the exact same checks as the store indexer — manifest JSON & schema,
Docker image availability (main and sub-containers), cover image (format,
dimensions, size) and the code rules — and reports every problem at once so
you can fix them in a single pass. It exits 0 when the integration is valid,
1 otherwise. A few things can only be confirmed once the repository is public
(public repo, the gladys-assistant-integration topic, and the manifest sitting
at the root of the default branch), and the tool tells you which ones. See the
integration store for
details.
- Fork this template (or use Use this template on GitHub).
- Edit the files in
src/devices/andgladys-assistant-integration.jsonfor your devices, and replacedocker_image/cover_imagewith your own. - Add the GitHub topic
gladys-assistant-integrationto your repo. - Release from the GitHub UI: open Actions → Release → Run workflow,
pick
patch,minorormajor. The workflow bumps the version everywhere (package.json+ manifestversion/docker_image), pushes thevX.Y.Ztag, and builds thelinux/amd64+linux/arm64image toghcr.io(:X.Y.Zand:latest). No local tag, no manual version edit. - The decentralized indexer picks up the new manifest
versionand Gladys offers a one-click install / update.
Prefer the terminal?
git tag v1.0.0 && git push --tagsstill works — the hand-pushed tag triggers the same multi-arch build. This path only publishes the Docker tags, though: it does not touchpackage.json,package-lock.jsonor the manifest. Bumpversion(anddocker_image) ingladys-assistant-integration.jsonand commit it before tagging, or the indexer will keep serving the old version. The Release workflow above does all of this for you.
Full documentation: https://gladysassistant.com (integrations developer guide).
- Requires Node.js ≥ 20 (uses the built-in global
fetch; no HTTP dep). - All external identifiers are prefixed with
ext:<selector>:— always build them withgladys.externalIds(type, platformId)(or the lower-levelgladys.externalId(suffix)); the server rejects anything else. DeriveplatformIdfrom the unique id the external platform gives you (serial, cloud id, MAC…), never from a hard-coded label. has_feedback: truefeatures should publish the state confirmed by the device; the template publishes the requested value for simplicity.- Replace
cover.pngwith your own 800×534 px image (≤150 KB, PNG or JPEG) before publishing. The bundled one is a plain gradient placeholder.
Apache-2.0