Skip to content

Quickstart ​

First steps with the nomos system Controller API, in JavaScript and with curl

This example logs in to the controller, reads all components, switches one component on and off again, follows the change and executes a scene. First in JavaScript over Socket.io, then the same steps with curl over HTTP.

A regular user may use every call in this example as well (see Permissions).

What you need ​

  • the address of the controller on the local network, here <controller-ip>
  • a user, here USERNAME and PASSWORD
  • the CID of a component that is safe to switch, such as a light. Data Model explains how to find the CID. The example uses C5.
  • optionally the ID of a scene you want to execute

JavaScript (Socket.io) ​

You need Node.js 18 or later and socket.io-client 4.6 or later:

bash
mkdir nomos-quickstart && cd nomos-quickstart
npm init -y
npm install socket.io-client@4

Save the program as quickstart.js:

javascript
// quickstart.js - Node.js 18 or later, npm install socket.io-client@4
const { io } = require('socket.io-client');

const HOST = process.env.NOMOS_HOST;          // address of the controller, e.g. 192.168.1.10
const USERNAME = process.env.NOMOS_USER;
const PASSWORD = process.env.NOMOS_PASSWORD;
const CID = process.env.NOMOS_CID;            // component to switch, e.g. C5
const SCENE_ID = process.env.NOMOS_SCENE;     // optional: scene to execute

const socket = io(`http://${HOST}/api/v1`, { path: '/socket.io-v4' });

// Sends an event and waits for the controller's answer
const call = (event, params = {}) => socket.timeout(15000).emitWithAck(event, params);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Live values: an array of {cid, property, value, content, unit}
socket.on('onComponentUpdate', (updates) => {
    for (const update of updates) {
        if (update.cid === CID) console.log('onComponentUpdate:', update);
    }
});

// The controller asks for a login on every new connection. Only then is auth accepted.
socket.on('stateChange', async (state) => {
    if (state.part !== 'app' || state.state !== 'User Authorization needed') return;
    try {
        // 1. Log in, then initialise the connection
        const auth = await call('auth', { username: USERNAME, password: PASSWORD });
        if (auth.errorCode) throw new Error(`auth: ${auth.errorCode} ${auth.errorText}`);
        await call('init', { language: 'en', appName: 'quickstart' });

        // 2. Read all components
        const components = await call('getAllComponents', { withProperties: false, withMappings: false });
        for (const c of components) console.log(c.cid, c.name, c.category);

        // 3. Switch a component on and off again
        console.log('on:', await call('componentUpdate', { cid: CID, property: 'state', value: true }));
        await sleep(3000);
        console.log('off:', await call('componentUpdate', { cid: CID, property: 'state', value: false }));
        await sleep(3000);

        // 4. Execute a scene
        if (SCENE_ID) console.log('scene:', await call('executeScene', { id: Number(SCENE_ID) }));
    } catch (err) {
        console.error(err.message);
    } finally {
        socket.close();
    }
});

socket.on('connect_error', (err) => console.error('connect_error:', err.message));

Run it with your details:

bash
NOMOS_HOST=<controller-ip> NOMOS_USER=USERNAME NOMOS_PASSWORD=PASSWORD NOMOS_CID=C5 node quickstart.js

The output looks roughly like this (shortened):

native_scene Scenes Automation
...
C5 Switch Switches
C6 Dimmer Lighting
C7 Temperatur Sensors
...
on: { C5: true }
onComponentUpdate: { cid: 'C5', property: 'state', content: 1, value: true }
off: { C5: true }
onComponentUpdate: { cid: 'C5', property: 'state', content: 0, value: false }

The steps in detail ​

  1. Log in: stateChange with User Authorization needed is followed by auth and init. Why the program waits for stateChange is explained under Connect and Authenticate.
  2. Read components: getAllComponents returns every component the user may see. With withProperties: false and withMappings: false the answer only holds master data and current values, without the description of the properties. The Data Model explains how a component is structured.
  3. Switch: componentUpdate sets a property. The answer holds true per CID if the controller accepted the command, and false if not, for example for an unknown CID or a missing permission. true does not yet mean the device has switched.
  4. Follow changes: What the device actually reports arrives as onComponentUpdate. The event carries a list of changes and arrives for every component the user may see, so the program filters by CID.
  5. Execute a scene: executeScene with the ID from getScenes. The answer true only arrives once the scene has run completely. For an unknown ID the controller answers {errorCode: 112, errorText: 'Not found'}. Error 116 (timeout) means the confirmation did not arrive, not that the scene did not start.

On failure every call answers with errorCode and errorText. Decide in your code by errorCode; errorText is meant for people and translated into the language from init. The list of error codes is on apidocs.

HTTP (curl) ​

The same calls are available over HTTP, only without events. All details are under HTTP API.

1. Log in and get a session ID

bash
curl -s -X POST -H "auth-username: USERNAME" -H "auth-password: PASSWORD" \
  http://<controller-ip>/api/v1/auth
json
{"sessionID":"<session-id>","userID":<user-id>}

userID is the ID of your user. The following calls send the session ID in the header x-nomos-sid.

2. Read components

bash
curl -s -X POST -H "x-nomos-sid: <session-id>" -H "content-type: application/json" \
  -d '{"withProperties":false,"withMappings":false}' \
  http://<controller-ip>/api/v1/getAllComponents
json
[ ...,
  {"cid":"C5","name":"Switch","category":"Switches","type":"Switch",
   "data":[{"value":false,"content":0,"lastUpdate":"2026-10-08T12:48:28.130Z","property":"state"}, ...],
   "rooms":[17], ...},
  ... ]

3. Switch

bash
curl -s -X POST -H "x-nomos-sid: <session-id>" -H "content-type: application/json" \
  -d '{"cid":"C5","property":"state","value":true}' \
  http://<controller-ip>/api/v1/componentUpdate
json
{"C5":true}

4. Query the value

Without events you query the value with getComponentData:

bash
curl -s -X POST -H "x-nomos-sid: <session-id>" -H "content-type: application/json" \
  -d '{"cid":"C5","property":"state"}' \
  http://<controller-ip>/api/v1/getComponentData
json
{"value":true,"content":1,"lastUpdate":"2026-10-08T12:49:05.877Z"}

Then switch off again with "value":false.

5. Execute a scene

bash
curl -s -X POST -H "x-nomos-sid: <session-id>" -H "content-type: application/json" \
  -d '{"id":4}' \
  http://<controller-ip>/api/v1/executeScene

The answer is true once the scene has run.

6. Log out

bash
curl -s -X POST -H "x-nomos-sid: <session-id>" http://<controller-ip>/api/v1/logout
json
true

The session ID is invalid afterwards.

Where to go next ​