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.
- 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
anytype - Implemented with async/await - code waits for async websocket response message before returning
- This package is used as the foundation of
matterbridge-loxone
- Fully typed TypeScript objects, avoiding the
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.
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.
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.
Requires a Loxone Miniserver with firmware version 11.2 or higher.
Uses token authentication with the Miniserver. Automatically attempts token refresh before expiry.
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
...
Key entrypoint to the module.
LoxoneClient(
host: string,
username: string,
password: string,
clientOptions: Partial<LoxoneClientOptions>
)| 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.
Initiates the connection to the Loxone Miniserver, negotiates session keys and encryption parameters, as well as attempts token authentication.
Goes through the following sequence
- Wire up events so LoxoneClient starts emitting connection and Loxone related events
- Checks the Loxone Miniserver generation and firmware version
- Connects the WebSocket connection
- Performs key exchange and authentication, and schedules automatic token refresh
- Enables keepalive (unless disabled by
clientOptions.keepAliveEnabled)
async connect(existingToken: string = "")| parameter | description |
|---|---|
| existingToken | if supplied, uses the supplied token instead of acquiring a new one |
Disconnects the connection and cleans up internal states.
async disconnect(preserveToken: boolean = false)| parameter | description |
|---|---|
| preserveToken | optional parameter to skip killing the obtained token so it remains valid after disconnection |
Retrieves the Loxone structure file (LoxAPP3.json)
async getStructureFile()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)
async parseStructureFile()Enables the streaming of binary event updates.
async enableUpdates()Sends a text command to the Miniserver and waits for the response till timeout (default: 5s, overridable). Automatically applies Command Encryption as needed.
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 |
TextMessage object with the response to the command, or an exception.
Retrieves a file from the Miniserver and waits for the response till timeout (default: 5s, overridable).
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 |
FileMessage object with the file contents, or an exception.
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.
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 |
TextMessage object with the result of the operation, or an exception.
Sets the log level. By default it is set to INFO.
setLogLevel(level: LogLevel)| parameter | description |
|---|---|
| level | Loglevel to set logging to. Uses the node-ansi-logger module |
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.
addUuidToWatchList(uuid: string | string[])| parameter | description |
|---|---|
| uuid | UUID string or array of strings to add to the watchlist |
Removes UUIDs from the watch list.
removeUuidFromWatchList(uuid: string | string[])| parameter | description |
|---|---|
| uuid | UUID string or array of strings to remove from the watchlist |
Checks whether the token is still valid.
async checkToken(token: string = "")| parameter | description |
|---|---|
| token | If supplied, checks the supplied token instead of the remembered (active) one |
Refreshes the active token if it is still valid. If not, attempts to acquire a new one.
async refreshToken()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.
While the author took special care to follow Loxone official documentation, use this module at your own risk.
This module is heavily inspired by and based on the node-lox-ws-api module: https://github.com/alladdin/node-lox-ws-api