Skip to content

andrasg/loxone-ts-api

Repository files navigation

loxone-ts-api

A Node module written in TypeScript for facilitating communication with Loxone Miniservers. Communication is done using http and WebSockets.

Currently only implemented http/ws communication to enable support for Gen.1 and Gen.2 Miniservers. https/wss communication currently not supported, but planned.

Key featrues

  • Connects to the Loxone Miniserver via WebSocket
    • Support for both Gen.1 and Gen.2 Miniservers
    • Support for token-based auth, token refresh and token invalidation
    • Supports automatic reconnect
    • Automatically maintains connection upon disconnect or error
  • Event emitting
    • emits events on key connection events
    • emits events for message received
    • ability to filter events to specific UUIDs
  • Loxone structure file parsing
    • Ability to read and parse structure file
    • Provides rich TypeScript classes representing Loxone rooms, controls and states
    • Supplies rich event context for each event (value or text update)
  • Control any Loxone control
    • Supports websocket-based control of any Loxone control
  • Nerdy stuff
    • Fully typed TypeScript objects, avoiding the any type
    • Implemented with async/await - code waits for async websocket response message before returning
    • This package is used as the foundation of matterbridge-loxone

Structure file parsing

After calling LoxoneClient.parseStructureFile(), the client will read the LoxAPP3.json and parse all rooms, their available controls and states associated. These can be read on the client object through the rooms, controls and states collections. It will also start enriching the received events with the associates State object that contains details about the state, its associated control and the room the control is in.

Watchlist

By default the client will emit all events received via websocket. You can add status UUIDs to the watchlist by calling LoxoneClient.addUuidToWatchList(uuid). Upon adding items to the watchlist, the client will only log and emit events received for statuses associated with the watched UUIDs.

Error handling

The client tries to maintain the connection with the Miniserver even when network interruptions occur. Errors in command calls should not make the client crash.

Requirements

Requires a Loxone Miniserver with firmware version 11.2 or higher.

Authentication

Uses token authentication with the Miniserver. Automatically attempts token refresh before expiry.

Usage examples

import { AnsiLogger, LogLevel, TimestampFormat } from "node-ansi-logger";
import LoxoneClient from "./LoxoneClient.js";

let log = new AnsiLogger({logName: "workbench", logTimestampFormat: TimestampFormat.TIME_MILLIS});

// instantiate the client
let client = new LoxoneClient("192.168.1.253:80", "user", "pass");

// sets log level to debug for more verbose logging
client.setLogLevel(LogLevel.DEBUG);

// subscribe to basic events
client.on('disconnected', () => {
    log.warn('Loxone client disconnected');
});
client.on('error', (error) => {
    log.error(`Loxone client error: ${error.message}`, error);
});

// initiate connection
await client.connect();

// gets acquired token
const token = client.auth.tokenHandler.token; 

// disconnects and skips invalidation of token
await client.disconnect(true); 

// uses supplied token for auth instead of acquiring a new one
await client.connect(token); 

// sets a switch to on
await client.control("90f7abe3-8772-476d-b1dd-a5c1c4cf1ed9", "on");

// subscribe to Loxone value updates
client.on('event_value', (event) => {
    log.info(`Received value event: ${event.uuid.stringValue}`);
    log.info(`  Room: ${event.state?.parentControl?.room?.name}`);
    log.info(`  Control: ${event.state?.parentControl?.name}`);
    log.info(`  State: ${event.state?.name}`);
    log.info(`  Event path: ${event.toPath()}`);
    log.info(`  Full event: ${event.toString()}`);
});

// initiates streaming of events
await client.enablesUpdates(); 

// disconnects and kills token
await client.disconnect(); 

This will yield a log output similar to:

...
[09:04:59.568] [LoxoneClient] Loxone event: Not Assigned/Control/Subcontrol/total = 2446.4848200150127
[09:04:59.568] [workbench] Received value event: 1cc4333c-02c9-60ec-05ff6d4c46418939
[09:04:59.569] [workbench]   Room: Not Assigned
[09:04:59.569] [workbench]   Control: Control/Subcontrol
[09:04:59.569] [workbench]   State: total
[09:04:59.570] [workbench]   Event path: Not Assigned/Control/Subcontrol/total
[09:04:59.570] [workbench]   Full event: Not Assigned/Control/Subcontrol/total = 2446.4848200150127
...

API surface

LoxoneClient

Key entrypoint to the module.

    LoxoneClient(
        host: string,
        username: string,
        password: string,
        clientOptions: Partial<LoxoneClientOptions>
    )

Parameters

parameter description
host IP address or hostname of the Loxone Miniserver
username username to use
password password for the user
clientOptions.autoReconnectEnabled optional parameter to override the default behavior of automatically reconnecting on failure/disconnection
clientOptions.keepAliveEnabled optional parameter to override the default behavior of enabling a 15 second keepalive
clientOptions.messageLogEnabled optional parameter to override the default behavior of enabling a logging of messages and responses
clientOptions.logAllEvents optional parameter to log all value and text update events to the console
clientOptions.maintainLatestEvents optional paraneter to override the default behavior of maintaining the latest event for each control

Instantiating a LoxoneClient instance does not trigger any network communication.

LoxoneClient.connect()

Initiates the connection to the Loxone Miniserver, negotiates session keys and encryption parameters, as well as attempts token authentication.

Goes through the following sequence

  1. Wire up events so LoxoneClient starts emitting connection and Loxone related events
  2. Checks the Loxone Miniserver generation and firmware version
  3. Connects the WebSocket connection
  4. Performs key exchange and authentication, and schedules automatic token refresh
  5. Enables keepalive (unless disabled by clientOptions.keepAliveEnabled)

Parameters

async connect(existingToken: string = "")
parameter description
existingToken if supplied, uses the supplied token instead of acquiring a new one

LoxoneClient.disconnect()

Disconnects the connection and cleans up internal states.

Parameters

async disconnect(preserveToken: boolean = false)
parameter description
preserveToken optional parameter to skip killing the obtained token so it remains valid after disconnection

LoxoneClient.getStructureFile()

Retrieves the Loxone structure file (LoxAPP3.json)

Parameters

async getStructureFile()

LoxoneClient.parseStructureFile()

Parses the Loxone structure file (LoxAPP3.json). After calling this method, event updates will contain enriched information about the room, control and states. Each State of all Controls will also start remembering the latest event received (unless disabled by clientOptions.maintainLatestEvents)

Parameters

async parseStructureFile()

LoxoneClient.enableUpdates()

Enables the streaming of binary event updates.

Parameters

async enableUpdates()

LoxoneClient.sendTextCommand()

Sends a text command to the Miniserver and waits for the response till timeout (default: 5s, overridable). Automatically applies Command Encryption as needed.

Parameters

async sendTextCommand(command: string, timeoutOverride = this.COMMAND_TIMEOUT): Promise<TextMessage>
parameter description
command The Loxone command to execute
timeoutOverride optional parameter allowing override of the default 5s timeout. Unit is milliseconds

Returns

TextMessage object with the response to the command, or an exception.

LoxoneClient.sendFileCommand()

Retrieves a file from the Miniserver and waits for the response till timeout (default: 5s, overridable).

Parameters

async sendFileCommand(filename: string, timeoutOverride = this.COMMAND_TIMEOUT): Promise<FileMessage>
parameter description
filename Filename of the file to be retrieved
timeoutOverride optional parameter allowing override of the default 5s timeout. Unit is milliseconds

Returns

FileMessage object with the file contents, or an exception.

LoxoneClient.control()

Executes a command on a Loxone control identified by its UUID and waits for the response till timeout (default: 5s, overridable)

See the Loxone structure file for documentation on possible commands.

Parameters

async control(uuid: UUID | string, command: string, timeoutOverride = this.COMMAND_TIMEOUT): Promise<TextMessage>
parameter description
uuid UUID of the Loxone control to operate
command The command to send
timeoutOverride optional parameter allowing override of the default 5s timeout. Unit is milliseconds

Returns

TextMessage object with the result of the operation, or an exception.

LoxoneClient.setLogLevel()

Sets the log level. By default it is set to INFO.

Parameters

setLogLevel(level: LogLevel)
parameter description
level Loglevel to set logging to. Uses the node-ansi-logger module

LoxoneClient.addUuidToWatchList()

Adds UUIDs to the watch list. Value and text update events will only be emitted for these UUIDs. If the watchlist is empty, all events will be emitted.

Parameters

addUuidToWatchList(uuid: string | string[])
parameter description
uuid UUID string or array of strings to add to the watchlist

LoxoneClient.removeUuidFromWatchList()

Removes UUIDs from the watch list.

Parameters

removeUuidFromWatchList(uuid: string | string[])
parameter description
uuid UUID string or array of strings to remove from the watchlist

LoxoneClient.checkToken()

Checks whether the token is still valid.

Parameters

async checkToken(token: string = "")
parameter description
token If supplied, checks the supplied token instead of the remembered (active) one

LoxoneClient.refreshToken()

Refreshes the active token if it is still valid. If not, attempts to acquire a new one.

Parameters

async refreshToken()

Events

The LoxoneClient emits the following events:

  connected: () => void;

Fires when the connection is successfully established.

  authenticated: () => void;

Fires when authentication was successful.

  ready: () => void;

Fires when LoxoneClient is ready to receive commands.

  disconnected: (reason: string) => void;

Fires when the underlying WebSocket is disconnected.

  error: (err: Error) => void;

Fires when a WebSocket error is encountered.

  header: (header: ParsedHeader) => void;

Fires when a header message is received.

  keepalive: (header: ParsedHeader) => void;

Fires when a keepalive message is received.

  text_message: (text: TextMessage) => void;

Fires when a text message is received on the WebSocket channel.

  file_message: (file: FileMessage) => void;

Fires when a file message is received on the WebSocket channel.

  event_table_values: (eventTable: LoxoneValueEvent[]) => void;
  event_table_text: (eventTable: LoxoneTextEvent[]) => void;
  event_table_day_timer: (eventTable: LoxoneDayTimerEvent[]) => void;
  event_table_weather: (eventTable: LoxoneWeatherEvent[]) => void;

Fires when an event update message is received on the WebSocket channel. EventTables can contain multiple update events of the same kind.

  stateChanged: (newState: string) => void;

Fires when the LoxoneClient changes its state. Possible states are:

  • disconnected
  • disconnecting
  • connecting
  • connected
  • authenticating
  • authenticated
  • ready
  • reconnecting
  • error
  event_value: (event: LoxoneValueEvent) => void;
  event_text: (event: LoxoneTextEvent) => void;

Fires when Loxone value or text update events are received. Events can be filtered using the watchlist functionality (addUuidToWatchList() and removeUuidFromWatchList()). If the watchlist contains any items, events event_value and event_text events are only emitted for the UUIDs that are on the watchlist. If the watchlist is empty, events are emitted for all value and text updates.

Disclaimer

While the author took special care to follow Loxone official documentation, use this module at your own risk.

Acknowledgements, credits

This module is heavily inspired by and based on the node-lox-ws-api module: https://github.com/alladdin/node-lox-ws-api

About

A node module written in TypeScript to communicate with Loxone Miniservers via websockets.

Topics

Resources

License

Stars

Watchers

Forks