Lox Nexus

Matter bridge plugin

Shows devices you define in Nexus to Alexa, Google Home, Apple Home and Home Assistant as a Matter bridge, on your own network without a cloud or skill. Their state comes from Nexus (for example a Loxone output); what those apps command comes back into Nexus as sensors.

What it does

  • Sensors: commands from the apps per device: on/off, brightness, colour temperature, colour, a blind's target position and slat angle, a thermostat's setpoints and mode, a fan's speed, lock and unlock requests, opening and closing a valve, a wallbox's charging release, current and mode, and a chime played from an app (a ring pulse and its sound).
  • Actuators: each device's state for the apps: the same values back, plus temperature, humidity, illuminance, pressure, flow, air quality, CO₂ and PM2.5, contact, motion, smoke and CO alarms, water leaks, rain, frost, battery levels, button and doorbell presses that start routines, and energy: power, energy, voltage and current of meters, PV systems, home batteries, wallboxes and heat pumps, and a wallbox's car and session.
  • Catalog: one folder per device with exactly the signals its type has.
  • Panel: where pairing stands ("Not paired yet", or a pairing window counting down to its end), the QR code and code (while the bridge's own code works), the paired apps with a Remove button each, and every device with its id, last command and last state, with Edit and Remove buttons. It refreshes by itself on pairing, pairing windows, controllers, device changes and new commands and states.
  • Actions: Add device, Edit device, Remove device (while the bridge runs, no restart), Open pairing window (15 minutes, to add a second app) and Remove pairing.

Before you start

  • Nexus with host networking (network_mode: host, as in compose.yaml) and IPv6 enabled on the host, on the same network segment (VLAN) as your Echo, Google or Apple hub. mDNS (UDP 5353) must reach Nexus, and the UDP port (5540) must be open on the host's firewall.
  • A Matter controller: an Echo of the 4th generation or newer, a Google Nest hub, an Apple TV or HomePod, or Home Assistant with its Matter integration.
  • UDP port 5540 free on the host, or another one in the settings (Home Assistant's Matter Server and Matterbridge use 5540 too).
  • About 180–230 MB of memory per running instance; one instance is enough for 50 devices.

Configuration

Field Description
Bridge name (name) optional; default Lox Nexus How the bridge shows in the apps, at most 32 bytes.
UDP port (port) optional; default 5540 The Matter port, 1024 to 65535. Change it only when another Matter program on the host uses 5540, e.g. to 5550.

Devices are not settings: add them with Add device on the instance page (name, type, where a kind has several types the one you want, e.g. Light → Dimmable, for door locks Allow unlocking, for battery-powered sensors and buttons Battery), at most 50 (Alexa's limit for one bridge).

Sensors and actuators

Kind Name (id) Value What it is
sensor On/off from controllers (on-off) boolean An app switched a light, plug or fan on or off.
sensor Brightness % from controllers (brightness) number An app dimmed a light (1–100), or 0 when it switched it off.
sensor Colour temperature K from controllers (color-temperature) number An app set a tunable white light's colour temperature.
sensor Tunable white from controllers (tunable-white) tunableWhite Colour temperature and brightness together, for a Loxone tunable-white actuator.
sensor Target position % from controllers (position) number Where an app wants the blind, in % closed (0 open, 100 closed).
sensor Heating setpoint °C from controllers (setpoint) number The temperature an app set on the thermostat.
sensor Fan speed % from controllers (fan-speed) number The speed an app set on a fan (0–100).
sensor Target slat angle % from controllers (tilt) number Where an app wants the slats, in % closed.
sensor Colour from controllers (color) rgbw The colour an app set, brightness included, for a Loxone RGBW actuator.
sensor Cooling setpoint °C from controllers (cooling-setpoint) number The temperature an app set to cool to.
sensor Mode from controllers (mode) string The thermostat mode an app picked: off, heat, cool or auto.
sensor Open or close from controllers (valve) boolean true when an app opens the valve, false when it closes it.
sensor Charging enabled from controllers (charging-enabled) boolean Whether an app enabled or disabled the wallbox's charging.
sensor Maximum charging current A from controllers (max-current) number The current an app allowed when it enabled charging.
sensor Charging mode from controllers (charging-mode) string manual, time-of-use or solar.
sensor Ring from controllers (ring) boolean A one-second pulse each time an app plays the chime.
sensor Chime sound from controllers (chime-sound) number The sound an app played, 1–4, just before the ring.
sensor Chime on from controllers (chime-enabled) boolean An app switched the chime on or off.
sensor Lock request from controllers (lock) boolean true to lock, false to unlock (only if the lock allows unlocking).
actuator On/off state to controllers (on-off) boolean Whether the light, plug or fan is on.
actuator Brightness % to controllers (brightness) number The light's brightness; 0 shows it off.
actuator Colour temperature K to controllers (color-temperature) number The light's colour temperature (2700–6500 K).
actuator Tunable white to controllers (tunable-white) tunableWhite Colour temperature and brightness together.
actuator Current position % to controllers (position) number Where the blind is, in % closed.
actuator Temperature °C to controllers (temperature) number A temperature sensor's value, or a thermostat's room temperature.
actuator Humidity % to controllers (humidity) number A humidity sensor's value.
actuator Open to controllers (contact) boolean On while the door or window is open.
actuator Occupied to controllers (occupancy) boolean On while motion is detected.
actuator Heating setpoint °C to controllers (setpoint) number The thermostat's setpoint (7–30 °C).
actuator Fan speed % to controllers (fan-speed) number The fan's speed; 0 shows it off.
actuator Locked to controllers (locked) boolean Whether the lock is locked.
actuator Smoke alarm to controllers (smoke) boolean A smoke alarm Nexus reports, e.g. from Loxone's fire alarm.
actuator CO alarm to controllers (co) boolean A carbon monoxide alarm Nexus reports.
actuator Leak to controllers (leak) boolean On while a water leak is detected.
actuator Current slat angle % to controllers (tilt) number Where the slats are, in % closed.
actuator Colour to controllers (color) rgbw The light's colour from a Loxone RGBW actuator; all 0 shows it off.
actuator Cooling setpoint °C to controllers (cooling-setpoint) number The thermostat's cooling setpoint (16–32 °C).
actuator Mode to controllers (mode) string The thermostat's mode: off, heat, cool or auto.
actuator Valve open to controllers (valve) boolean Whether the valve is open.
actuator Air quality level to controllers (air-quality) number 1 good to 6 extremely poor; without it, the level follows CO₂ and PM2.5.
actuator CO₂ ppm to controllers (co2) number The CO₂ concentration.
actuator PM2.5 µg/m³ to controllers (pm25) number The fine dust concentration.
actuator Illuminance lx to controllers (illuminance) number A light sensor's brightness in lux.
actuator Pressure hPa to controllers (pressure) number A pressure sensor's value in hPa.
actuator Flow m³/h to controllers (flow) number A flow sensor's value in m³/h.
actuator Rain to controllers (rain) boolean On while rain is detected.
actuator Frost to controllers (freeze) boolean On while a water freeze detector warns of frost.
actuator Battery % to controllers (battery) number The battery level of a sensor, button or doorbell added with Battery, or a home battery's state of charge.
actuator Chime on to controllers (chime-enabled) boolean Whether the chime is on; off ignores plays.
actuator Press to controllers (press) boolean Each true is a short button press, to start routines.
actuator Long press to controllers (long-press) boolean Each true is a long button press.
actuator Power W to controllers (power) number Power taken (positive) or given (negative): a meter, battery, wallbox or heat pump.
actuator PV power W to controllers (production) number The power a PV system produces.
actuator Energy imported kWh to controllers (energy-imported) number Total energy taken: grid import, a battery's charge, a wallbox's or heat pump's use.
actuator Energy exported kWh to controllers (energy-exported) number Total energy given: feed-in, PV production, a battery's discharge.
actuator Voltage V to controllers (voltage) number A meter's voltage.
actuator Current A to controllers (current) number A meter's current.
actuator Car plugged in to controllers (plugged-in) boolean Whether a car is at the wallbox; plugging in starts a session.
actuator Charging to controllers (charging) boolean Whether the car charges.
actuator Charging enabled to controllers (charging-enabled) boolean Whether the wallbox may charge.
actuator Maximum charging current A to controllers (max-current) number The current the wallbox may charge with (6–32 A).
actuator Charging mode to controllers (charging-mode) string manual, time-of-use or solar.
actuator Session energy kWh to controllers (session-energy) number The energy charged since the car was plugged in.

Matter device types

Every device type matter.js 0.18 knows (it follows Matter 1.6.1, so this covers every type up to 1.5 and the newest ones), and whether the bridge offers it. What an app shows of a type is up to the app; the newer the type, the fewer apps know it.

Matter device type Id In the bridge
Lighting
On/Off Light 0x0100 on-off-light
Dimmable Light 0x0101 dimmable-light
Color Temperature Light 0x010C color-temperature-light
Extended Color Light 0x010D color-light
Plugs and wall controls
On/Off Plug-in Unit 0x010A plug
Dimmable Plug-in Unit 0x010B dimmable-plug
Mounted On/Off Control 0x010F wall-switch
Mounted Dimmable Load Control 0x0110 wall-dimmer
Pump 0x0303 not yet; easy (on/off and a level like a dimmer, with pressure or flow), few apps show pumps
Closures
Window Covering 0x0202 window-covering, venetian-blind
Door Lock 0x000A door-lock
Closure 0x0230 not yet; medium: Matter's newer garage doors, gates and windows, apps are only starting to support them
Closure Panel 0x0231 not yet; part of a closure (a panel or leaf), comes with it
Heating, cooling and air
Thermostat 0x0301 thermostat, thermostat-heat-cool
Fan 0x002B fan
Heat Pump 0x0309 heat-pump
Room Air Conditioner 0x0072 not yet; medium: the heating and cooling thermostat plus on/off and a fan
Air Purifier 0x002D not yet; medium: a fan plus filter state and air quality
Water Heater 0x050F not yet; medium: a heating thermostat plus tank state, boost and modes
Sensors
Temperature Sensor 0x0302 temperature-sensor
Humidity Sensor 0x0307 humidity-sensor
Light Sensor 0x0106 light-sensor
Pressure Sensor 0x0305 pressure-sensor
Flow Sensor 0x0306 flow-sensor
Air Quality Sensor 0x002C air-quality-sensor
Contact Sensor 0x0015 contact-sensor
Occupancy Sensor 0x0107 occupancy-sensor
Smoke CO Alarm 0x0076 smoke-co-alarm
Water Leak Detector 0x0043 water-leak-detector
Rain Sensor 0x0044 rain-sensor
Water Freeze Detector 0x0041 water-freeze-detector
Soil Sensor 0x0045 not yet; easy (soil moisture and temperature), hardly any app shows it
Buttons and doorbells
Generic Switch 0x000F generic-switch
Doorbell 0x0148 doorbell
Chime 0x0146 chime
Audio Doorbell, Video Doorbell, Intercom 0x0141, 0x0143, 0x0140 not planned: need audio or video streaming
Camera, Floodlight Camera, Snapshot Camera 0x0142, 0x0144, 0x0145 not planned: need video streaming
Water
Water Valve 0x0042 water-valve
Irrigation System 0x0040 not yet; medium: several valve zones with flow
Energy
Electrical Meter 0x0514 electrical-meter
Solar Power 0x0017 solar-power
Battery Storage 0x0018 battery-storage
Energy EVSE (wallbox) 0x050C evse
Electrical Sensor, Device Energy Management, Power Source 0x0510, 0x050D, 0x0011 part of the energy types (a power source also of a sensor with a battery)
Electrical Utility Meter, Meter Reference Point, Electrical Energy Tariff 0x0511, 0x0512, 0x0513 not planned: a utility's meter identification and tariffs, which Nexus has no source for
Appliances
Refrigerator, Temperature Controlled Cabinet 0x0070, 0x0071 not planned: appliance states, programs and modes have no counterpart in Nexus
Laundry Washer, Laundry Dryer, Dishwasher 0x0073, 0x007C, 0x0075 not planned, as above
Oven, Cooktop, Cook Surface, Microwave Oven, Extractor Hood 0x007B, 0x0078, 0x0077, 0x0079, 0x007A not planned, as above
Robotic Vacuum Cleaner 0x0074 not planned, as above
Media
Speaker, Basic Video Player, Casting Video Player, Content App 0x0022, 0x0028, 0x0023, 0x0024 not planned: media playback and apps
Controllers
On/Off Light Switch, Dimmer Switch, Color Dimmer Switch 0x0103, 0x0104, 0x0105 not planned: they switch other Matter devices directly (bindings), which apps don't offer for bridges; use a button for routines
Control Bridge, On/Off Sensor 0x0840, 0x0850 not planned, as above
Door Lock Controller, Window Covering Controller, Thermostat Controller, Pump Controller, Closure Controller 0x000B, 0x0203, 0x030A, 0x0304, 0x023E not planned, as above
Camera Controller, Video Remote Control, Casting Video Client 0x0147, 0x002A, 0x0029 not planned, as above
Other
Mode Select 0x0027 not yet; easy (named modes both ways), but the big apps don't show it
Infrastructure
Root Node, Aggregator, Bridged Node 0x0016, 0x000E, 0x0013 what the bridge itself is made of
OTA Requestor, OTA Provider 0x0012, 0x0014 not applicable: firmware updates
Secondary Network Interface, Network Infrastructure Manager, Thread Border Router, Joint Fabric Administrator 0x0019, 0x0090, 0x0091, 0x0130 not applicable: network infrastructure

Good to know

  • To pair, add a Matter device in the app and scan the QR code on the instance page, or type the 11-digit code. Alexa warns that the bridge is not certified; that is expected.
  • Renaming a device keeps it in the apps (Alexa may show the old name until you rename it there); removing and adding it again makes a new device, and its routines are lost.
  • Wire each command sensor and its state actuator: a command that matches the state the bridge shows sends nothing new, so the state must come back from Loxone.
  • Door locks refuse unlocking from the apps unless Allow unlocking is on. The smoke and CO alarm only forwards what Nexus reports; it is no replacement for a certified smoke detector.
  • While a pairing window is open, anyone on your network who sees the code could pair. Alexa can't find the bridge? Usually mDNS or IPv6 doesn't reach it (see the reference).

More

The full reference (managing devices, what each device type shows in the apps and what Alexa does with it, how values convert, pairing more apps and removing them, the panel, networking and troubleshooting, storage, memory, limits, security notes and development notes) is in REFERENCE.md next to this file, and on the plugin's page in the Nexus documentation.

Managing devices

Devices are kept in the plugin store (devices), not in the settings, and changed with actions on the instance page while the bridge runs; none of them restarts the instance or touches a pairing. Their buttons are in the Status card: Add device above the Devices table, Edit and Remove on each row, Open pairing window in the Pairing section and Remove on each controller's row.

Action Input What it does
Add device (add-device) type, name; for a kind with several types the type in the kind's field (see below); for a door lock allowUnlock (default off); for sensors and buttons battery (default off) Adds a device, at most 50 per bridge (Alexa's limit). Names are unique ignoring case, at most 32 bytes. The type list is short: close types are one entry with a second choice, which the form asks for ("Choose…") before adding. The form shows Allow unlocking only when Door lock is chosen, and Battery only for sensors and buttons; neither the type nor the battery can be changed later.
Edit device (edit-device) device (id), name Renames a device; a door lock keeps whether it may be unlocked. Asks before saving. The Edit button on each row of the Devices table fills it in. The type can't change: remove the device and add a new one. If the endpoint refuses a change, the device keeps what it had.
Edit lock (edit-lock) device (id), name, allowUnlock A door lock's Edit: renames it and allows or forbids unlocking from the apps. Refuses a device that isn't a lock. Turning unlocking on is written to the instance log as a warning.
Remove device (remove-device) device (id) Removes a device after a confirmation, with what the bridge remembered of it. The Remove button on each row fills it in.
  • Kinds with several types. type is the kind, and the type goes in the kind's own field:

    Kind (type) Field Types
    Light (lights) light dimmable-light, on-off-light, color-temperature-light, color-light
    Plug (plugs) plug plug, dimmable-plug
    Wall switch or dimmer (wall-controls) wallControl wall-switch, wall-dimmer
    Blind or shutter (blinds) blind window-covering, venetian-blind
    Thermostat (thermostats) thermostat thermostat, thermostat-heat-cool
    Sensor (sensors) sensor temperature-sensor, humidity-sensor, light-sensor, pressure-sensor, flow-sensor, air-quality-sensor
    Leak, rain or frost sensor (water-sensors) waterSensor water-leak-detector, rain-sensor, water-freeze-detector
    Button or doorbell (buttons) button generic-switch, doorbell
    Energy meter (energy-meters) energyMeter electrical-meter, solar-power, battery-storage

    Every other type is a kind of its own, with the type as type, e.g. { "type": "door-lock", "name": "Front door" }; a kind with several types looks like { "type": "lights", "light": "dimmable-light", "name": "Kitchen" }. (Up to plugin version 0.1.0, type was the type itself.)

  • Ids. A new device gets an id from its name and a short random suffix, e.g. kitchen-light-3f2a. Its signals refer to it, and its Matter identity (endpoint, unique id, serial number) derives from it, so neither changes when the device is renamed.

  • Adding shows the device to every paired app at once: a Matter controller sees it within a second (measured with matter.js). The Alexa app may take a minute or need Discover devices.

  • Renaming keeps the device, its routines and its signals. The bridge reports the new label (Matter's NodeLabel) to the paired apps right away, but apps often keep the name they gave the device when it was added: rename it in the app too, or remove it there and discover again.

  • Removing takes the device from every app (routines using it stop working). Its signals in Nexus stay, in the error state ("the bridge has no device …"), until you remove them.

  • From an older version. Devices that the first version kept in the settings move into the bridge's own storage once (config version 2), with their name as id (what their signals refer to) and the Matter identity they had, so a paired Alexa keeps them. That happens at the first start, or when the settings are saved before it; either way nothing is lost.

Device types

Each device is one bridged Matter device. Its type decides what the apps show and which signals it has.

Type (type) In the apps Sensors (commands) Actuators (states) Starts as
On/off light (on-off-light) a light with on/off on-off on-off off
Dimmable light (dimmable-light) a light with brightness on-off, brightness on-off, brightness off
Tunable white light (color-temperature-light) a light with brightness and white tone on-off, brightness, color-temperature, tunable-white the same four off, 4000 K
Colour light (RGB) (color-light) a colour light (extended colour light) on-off, brightness, color-temperature, color the same four off, 4000 K
Plug (on/off) (plug) a smart plug on-off on-off off
Dimmable plug (dimmable-plug) a plug with brightness on-off, brightness on-off, brightness off
Wall switch (on/off) (wall-switch) a mounted on/off control (Matter 1.4) on-off on-off off
Wall dimmer (wall-dimmer) a mounted dimmable load control (Matter 1.4) on-off, brightness on-off, brightness off
Window covering (lift position) (window-covering) a blind or shutter with a position position position position unknown
Blind with slats (lift and tilt) (venetian-blind) an exterior venetian blind with position and slat angle position, tilt position, tilt positions unknown
Thermostat (heating) (thermostat) a heating thermostat setpoint temperature, setpoint room temperature unknown, setpoint 20 °C
Thermostat (heating and cooling) (thermostat-heat-cool) a thermostat with heat, cool, auto and off setpoint, cooling-setpoint, mode temperature, setpoint, cooling-setpoint, mode heat, room temperature unknown, setpoints 20 and 26 °C
Fan (fan) a fan with speed (off, low, medium, high, or %) on-off, fan-speed on-off, fan-speed off
Water valve (water-valve) a water valve (Matter 1.3) valve valve unknown
Door lock (door-lock) a lock lock locked unknown
Temperature sensor (temperature-sensor) a temperature sensor temperature unknown
Humidity sensor (humidity-sensor) a humidity sensor humidity unknown
Light sensor (lux) (light-sensor) an illuminance sensor illuminance unknown
Pressure sensor (pressure-sensor) a pressure sensor pressure unknown
Flow sensor (flow-sensor) a flow sensor flow unknown
Air quality sensor (air-quality-sensor) an air quality sensor with CO₂ and PM2.5 (Matter 1.2) air-quality, co2, pm25 unknown
Contact sensor (door, window) (contact-sensor) a contact sensor contact closed
Motion (occupancy) sensor (occupancy-sensor) a motion sensor occupancy no motion
Smoke and CO alarm (smoke-co-alarm) a smoke and carbon monoxide alarm (Matter 1.2) smoke, co normal
Water leak detector (water-leak-detector) a leak sensor (Matter 1.3) leak dry
Rain sensor (rain-sensor) a rain sensor (Matter 1.3) rain dry
Water freeze detector (water-freeze-detector) a frost sensor (Matter 1.3) freeze no frost
Button (generic switch) (generic-switch) a button for routines press, long-press
Doorbell (doorbell) a doorbell (a newer Matter type) press
Chime (bell) (chime) a chime with four sounds (a newer Matter type) ring, chime-sound, chime-enabled chime-enabled on, sound 1
Electricity meter (electrical-meter) an electrical meter (one of the newest Matter types) and electrical sensor power, energy-imported, energy-exported, voltage, current unknown
Solar power (PV) (solar-power) a PV system (Matter 1.4) with its power source and electrical sensor production, energy-exported unknown
Battery storage (battery-storage) a home battery (Matter 1.4) with its rechargeable battery, electrical sensor and energy management power, battery, energy-imported, energy-exported unknown
Wallbox (EV charger) (evse) an EV charger (Matter 1.3) with its electrical sensor, power source and energy management charging-enabled, max-current, charging-mode plugged-in, charging, charging-enabled, max-current, charging-mode, power, energy-imported, session-energy no car, charging enabled at 16 A, manual
Heat pump (heat-pump) a heat pump (Matter 1.4) with a heating and cooling thermostat below it setpoint, cooling-setpoint, mode temperature, setpoint, cooling-setpoint, mode, power, energy-imported as the heating and cooling thermostat; measurements unknown

Battery. Sensors, buttons and doorbells (every type above with actuators only, except the smoke and CO alarm, which reports itself as wired) can be added with Battery on: the device then also has a battery actuator, and the apps show its level (Matter's power source with a battery) and warn when it is low. Without it the device has no battery at all, as a mains-powered one.

"Unknown" is Matter's empty value: the apps show no reading rather than a made-up one; "Starts as" is what a new device shows before Nexus sends anything.

After a restart (a config change, an update) each device shows what it showed before, although Nexus doesn't replay values to actuators when an instance starts. matter.js stores on/off, brightness, colour, positions, fan speeds, setpoints and thermostat modes itself. For contacts, motion, locks, valves, alarms, leaks, rain, frost, measurements, air quality, battery levels, electrical measurements and a wallbox's car, supply and current the plugin keeps the last state Nexus sent (store keys state:<device id>): without it a restart would show every door closed and then "open" it again, which starts "door opens" routines although nothing happened, and temperatures would be unknown until Loxone happens to send again. After the factory reset that follows removing the last app, the bridge sets every state Nexus sent in this run again, in the order it sent them.

Sensors-only types are what start routines in Alexa ("when the front door opens, announce …"). Values without a Matter device type, such as a single power value of a device that is no energy device, can't be shown sensibly.

Energy devices. Matter composes its energy device types from utility types: a PV system is also a power source and an electrical sensor; battery storage, a wallbox and a heat pump add device energy management. The bridge puts these on the device's own endpoint (matter.js lists them), and the heat pump's thermostat on an endpoint below it; the power source names both. Energy management only says what kind of device it is and that it is online: a wallbox's has no forecast (null), a battery's and heat pump's no adjustment capability, so a controller's power adjustment request is refused. A battery's AC and battery sides, which Matter describes as two, are one. A wallbox keeps the charging targets an app sets (and returns them when asked) while it runs, but plans nothing with them; its next-charge attributes stay unknown.

A home battery's power source is rechargeable: its charge state follows the power (charging while positive, full at 100 %, otherwise not charging), and unlike a sensor's battery it never warns or asks for replacement when it runs low. Its voltage, times and charging current are unknown, and its capacity, which Matter can't leave unknown, is left out.

What the apps do with a type is up to them, and only real hardware shows it:

  • Smoke and CO alarm: it forwards an alarm state from Nexus, for example Loxone's fire and water alarm; it detects nothing itself and is no replacement for a certified smoke detector. Alexa announces smoke and CO alarms of Matter devices as proactive notifications.
  • Water leak detector: Amazon's list of Matter device types has no Alexa interface for it, so Alexa may show it without routines; Google Home, Apple Home and Home Assistant support it.
  • Door lock: Alexa asks for its own voice code before unlocking by voice (set in the Alexa app); Nexus keeps no PIN codes. Unlocking from any app is refused unless Allow unlocking is on for the lock.
  • Rain sensor, water freeze detector, water valve, doorbell, wall switch and wall dimmer: newer Matter types (1.3 and later). Apps that don't know them yet may show them as an unknown device or not at all; Home Assistant shows them.
  • Colour light: Alexa, Google Home and Apple Home set colours by hue and saturation or by x/y; both arrive as the same RGB value.
  • Energy devices (meter, PV, battery, wallbox, heat pump): Matter 1.3 and newer types for energy dashboards. Which apps show them, and what they show, varies and changes with their updates; Home Assistant reads the power and energy measurements. A device an app doesn't know may be missing in it or shown as unknown.
  • Button: apps that support Matter buttons (generic switches) offer presses as routine triggers; whether Alexa does for a bridged button could not be checked without an Echo.

How values convert

New signals suggest the unit and decimals of their value: °C with one decimal for temperatures and setpoints, % without decimals for humidity, brightness, position, fan speed and battery, K for color temperature, lx and hPa without decimals, and m³/h with one.

Signal Nexus Matter
on-off true on, false off OnOff onOff
brightness 0–100 %; 0 means off LevelControl currentLevel 1–254 plus OnOff. A command sends the effective brightness: the level in % while on (at least 1), 0 when switched off; "on at 30 %" from off sends on and 30 once each. A state of 0 switches the light off and keeps its level; above 0 switches it on at that level.
position 0–100 % closed (0 open, 100 closed), like a Loxone blind WindowCovering lift position in 1/100 %. Go to sends the target, open 0, close 100, and stop the position Nexus last reported (nothing while it is unknown), so wire the current position for stop to work. A state sets the current and the target position, so the apps don't show the blind moving.
temperature °C, e.g. 21.5 measuredValue or a thermostat's localTemperature in 1/100 °C, limited to -273.15 to 327.67
humidity % measuredValue in 1/100 %, limited to 0–100
contact true while open BooleanState stateValue, which Matter defines the other way round (true = contact closed). The plugin flips it, so a Loxone digital input "door open" wires directly.
occupancy true while motion is detected OccupancySensing occupied (passive infrared)
setpoint °C occupiedHeatingSetpoint in 1/100 °C, limited to the thermostat's 7–30 °C; a value outside is shown as the nearest limit
color-temperature Kelvin, e.g. 3000 ColorControl colorTemperatureMireds (1 000 000 / K), limited to 2700–6500 K; a command comes back in steps of 10 K
tunable-white Nexus's tunableWhite (temperature K, brightness %, fade time) Colour temperature, level and on/off together; brightness 0 is off. An app's action ("on at 30 %") can change several attributes, one after the other: the light reports once, as it ends up (fade time 0), with on/off and colour temperature only if they changed. The fade time Nexus sends is not used
fan-speed 0–100 % FanControl percentSetting (commands) and percentCurrent (state). Off, low, medium and high from an app become 0, 33, 66 and 100 %; a speed sets the mode (up to 33 % low, up to 66 % medium, above high). On/off is the speed above 0, sent only when it changes; "on" from Nexus goes back to the last speed above 0, from Nexus or an app (kept while the bridge runs)
lock true lock, false unlock DoorLock lock and unlock commands, sent on every request (also when the lock already shows that state). An unlock without Allow unlocking is answered with FAILURE and a LockOperationError event (restricted) and reaches nothing. A timed unlock (an app's "unlock for N seconds", only with Allow unlocking) arrives as false, and after the time matter.js relocks on its own: true arrives, and the apps show the lock locked at once, possibly before Loxone has locked it
locked true locked, false unlocked DoorLock lockState (unknown until Nexus first sends one)
smoke, co true while alarmed SmokeCoAlarm smokeState / coState critical or normal, expressedState (smoke before CO), and the SmokeAlarm, COAlarm and AllClear events
leak, rain, freeze true while a leak, rain or frost is detected BooleanState stateValue (true = detected), with its StateChange event
illuminance lux IlluminanceMeasurement measuredValue = 10 000 × log10(lx) + 1; below 1 lx is 0 (too dark to measure)
pressure hPa (mbar) PressureMeasurement measuredValue in 0.1 kPa, the same number as hPa
flow m³/h FlowMeasurement measuredValue in 0.1 m³/h, at least 0
battery 0–100 % PowerSource batPercentRemaining in half percent; batChargeLevel warning below 20 %, critical below 10 % (with batReplacementNeeded); its endpointList names the device. A battery level doesn't replace the reading in the panel's "last state"
tilt 0–100 % closed (0 open, slats horizontal; 100 closed) WindowCovering tilt position in 1/100 %, like position: go to sends the target, stop sends lift and slat positions Nexus last reported
color Nexus's rgbw: red, green and blue in %, brightness included A command is the light's colour at its brightness (all 0 when off; white 0), from whichever mode the app used: hue and saturation, CIE x/y, or a colour temperature as its RGB (matter.js's conversions). A state sets hue and saturation from the colour, and the brightness from its brightest channel. All 0 switches the light off and keeps its colour, so the next "on" from an app comes back in it; white alone (RGB 0, e.g. a number wired to the colour) is white at that brightness
cooling-setpoint °C occupiedCoolingSetpoint in 1/100 °C, limited to 16–32 °C. matter.js keeps the heating and cooling setpoints at least 1 °C apart in every mode: an app moving one may move the other (both come as commands), and a setpoint from Nexus closer than that moves the other one in the apps, without a command
mode text: off, heat, cool, auto Thermostat systemMode. A mode Nexus doesn't know (an app's fan only, dry) comes as Matter names it, e.g. fanonly; a state other than the four is refused. Map it to Loxone's numbers with a Map transform
valve true open, false closed ValveConfigurationAndControl Open and Close commands (sent on every request); the valve shows "transitioning" until Nexus reports currentState, or for at most a minute, after which it shows the last state Nexus sent again. A duration an app gives with Open is not kept: the valve stays open until closed
air-quality 1 good, 2 fair, 3 moderate, 4 poor, 5 very poor, 6 extremely poor, 0 unknown AirQuality airQuality. Until Nexus sends a level, and again after it sends 0, the level follows the worse of the readings: CO₂ up to 750, 1000, 1500, 2000 and 5000 ppm, PM2.5 up to 10, 20, 25, 50 and 75 µg/m³ (the European Air Quality Index's bands before the EEA's 2024 revision). For another scale, send a level of your own
power, production W ElectricalPowerMeasurement activePower in mW. power counts as Matter does: positive while the device takes power (a battery charging, a meter importing), negative while it gives power. production, a PV system's positive output, is shown negative, as power fed in. Invert a Fronius battery's power (positive while discharging) on the wire
voltage, current V, A voltage and activeCurrent in mV and mA. The current counts like the power: positive into the device; a meter's unsigned current from Loxone is shown as taken
energy-imported, energy-exported kWh, totals ElectricalEnergyMeasurement cumulativeEnergyImported / Exported in mWh, with the CumulativeEnergyMeasured event, which carries both totals the device has (the other one as last sent; missing until Nexus has sent it). A PV system only has exported energy (its production), a wallbox and a heat pump only imported, a meter and a battery both. After a restart the totals Nexus sent last are set again in one event
plugged-in, charging true, false EnergyEvse state: no car, plugged in (waiting while charging is enabled, wanting while it is disabled), charging; it follows the supply state at once when an app enables or disables. A car charging is plugged in, and one unplugged doesn't charge, whichever Loxone reports first. Plugging in starts a session (sessionId counts up) with the EVConnected event; charging starts and stops send EnergyTransferStarted and Stopped (with the energy of that transfer), unplugging EVNotDetected. The session's duration follows each report from Nexus, and goes on after a restart from where it was (the time the bridge was down is lost). After the factory reset that follows removing the last app, a car Nexus reported is plugged in again, which starts a new session
charging-enabled true, false A command: an app's Enable charging (true, with max-current) or Disable (false); the supply state changes at once. A state: the supply state (charging enabled or disabled). An app can enable charging until a time: then the bridge disables it and sends false (a time that has passed disables at once; one more than 24 days ahead is left to the app). A minimum current above the maximum is refused
max-current A EnergyEvse maximumChargeCurrent in mA, limited to 6 A and the 32 A circuit
session-energy kWh sessionEnergyCharged in mWh
charging-mode text: manual, time-of-use, solar EnergyEvseMode currentMode (modes 0, 1 and 2, with Matter's Manual, TimeOfUse and SolarCharging tags); an app's mode change is a command
co2, pm25 ppm, µg/m³ The concentration measurements' measuredValue (numeric, in air), at least 0
ring, chime-sound a one-second pulse (true, then false); the sound 1–4 An app's PlayChimeSound: first the sound it asked for (or the one selected in the app) as chime-sound (1 Ding dong, 2 Bell, 3 Gong, 4 Melody), then ring true, and false a second later; a play during the pulse makes it longer. Matter's ChimeStartedPlaying event is sent once matter.js offers it (0.18 doesn't). A sound that isn't installed is refused (NOT_FOUND), whether played or picked in an app; while the chime is off, plays are ignored. The sounds are only names for Loxone to tell apart: the bridge plays nothing, Loxone does the ringing. The ring starts off when the instance starts, so a restart during a pulse leaves no input on
chime-enabled true on, false off Chime enabled, both ways: an app switching the chime off or on is a command; Nexus can mute it (e.g. at night)
press, long-press each true is one press; false does nothing Switch events: InitialPress, ShortRelease and MultiPressComplete (two presses within 300 ms count as a double press); a long press holds for 1.2 s: InitialPress, LongPress, LongRelease. Presses are events, not states: nothing is remembered or replayed

A command from an app updates the bridge at once (Matter needs that) and goes to the sensor. A state from Nexus updates the bridge and is never sent back as a command, so a sensor and an actuator of the same device can both be wired to Loxone without a loop. Nexus drops a value equal to the previous one, and the bridge only reports changes: a command that matches what the bridge shows (Alexa says "on" while it shows on) sends nothing. Wire the state actuator as well, so the bridge shows what Loxone did.

A heating thermostat (thermostat) stays in heat mode: a mode change from an app (off, auto) is accepted by the bridge but not passed on. The heating and cooling thermostat passes modes both ways.

Sensor and actuator params

Every sensor and actuator has one param:

Param Description
device The device's id, as the Devices table shows it (e.g. kitchen-light-3f2a). Signal lists group the signals of one device under it.

A sensor for a device that doesn't exist, or whose type has no such command, goes into the error state with the reason (for example "Hall" is a plug (on/off), which gets no brightness commands); it follows devices removed while it runs. An actuator does the same, and each command it gets meanwhile fails with that message. Renaming never affects signals.

Catalog

One folder per device, labelled <name> (<type>), with the sensors first, then the actuators, e.g. Kitchen light: on/off from controllers and Kitchen light: brightness % to controllers. Every entry can be added as it is.

Pairing

The first app pairs while the bridge is not paired: in the Alexa app Devices → + → Add Device → Matter (in Google Home, Apple Home or Home Assistant: add a Matter device), then scan the QR code from the instance page or choose to type the 11-digit code. Alexa and Apple warn that the bridge is not certified (it uses the Matter test vendor id 0xFFF1); continue anyway. The devices then appear with their names.

  • A second app (multi-admin). Run Open pairing window: for 15 minutes the bridge accepts another pairing with the same code, and the panel shows the QR code and counts down to the end. The answer shows the code too. Alternatively, share the bridge from an app that already has it (the apps call it sharing or linking a Matter device); that app then shows a code of its own. While that window is open the panel says so instead of showing the bridge's code (which doesn't work then), and Open pairing window refuses until it has closed.
  • Removing an app. The Controllers table has a Remove button per app (or run Remove pairing with the fabric index the table shows). The bridge leaves that app's fabric at once; the app loses all the bridge's devices and its routines with them. Removing the bridge in the app itself works as well.
  • Removing the last app resets the bridge to factory settings: it forgets every pairing and waits to be paired again, with the same code. The reset puts every device back to how it was created; the bridge then sets their names, each lock's Allow unlocking and the states Nexus sent again. The reset takes a fraction of a second; a request that still meets it is answered "the bridge is resetting … try again in a few seconds".
  • The code (passcode and discriminator) is chosen once per instance and kept in the store (pairing). The keys and certificates of the pairings are kept there too (matter:bridge/…), so they survive restarts, config changes and updates, and travel in Nexus's backup.
  • Device identity comes from the device's id (see Managing devices): renaming keeps it, removing and adding a device makes a new one. A config change restarts the instance; the pairing is kept.

Panel

The page refreshes by itself when the bridge pairs or a controller is added or removed, when a pairing window opens or closes (the 15-minute one, and one a paired app opens to share the bridge), when devices are added, edited or removed, and on new commands and states. The end of an unpaired bridge's 48-hour window shows at the next regular refresh (within 30 s).

Section Shows
Pairing While not paired: a "Not paired yet" notice; if the pairing window of an unpaired bridge has closed (after 48 hours), it says so: run Open pairing window. Once paired: "Paired: yes" (green) and the pairing window: closed (grey), open for another app with a countdown to its end (amber), or, while a paired app shares the bridge (its own window and code), a note to use the code that app shows (blue). While the bridge isn't running: a notice saying so, or that it is resetting after the last app was removed.
Pairing code While not paired, or while a window opened with Open pairing window is open: the QR code, with the manual code (as 1234-567-8901).
Controllers One row per paired app: its name (the fabric's label, else the vendor: Amazon Alexa, Google Home, Apple Home), its vendor id in hex and its fabric index, with a Remove button.
Devices One row per device: name, id, type, the last command from an app and the last state from Nexus, each with its time, and the Edit and Remove buttons. Without devices: "No devices yet: use Add device". Devices with several values name the one, e.g. temperature 20.5 °C or heating setpoint 21 °C on a thermostat. The last state is the value Nexus sent, before any limit (a setpoint of 35 °C shows as sent and is shown to the apps as 30 °C).

Actions

Action Input What it does
Open pairing window (open-pairing-window) none Opens a 15-minute window for another app (while not paired: restarts the 48-hour window). Answers with the QR code and the manual pairing code.
Remove pairing (remove-pairing) fabricIndex (1–254) Removes that app's pairing, after a confirmation. Also offered as Remove on each row of the Controllers table.

Add, Edit and Remove device are described under Managing devices.

Networking

Matter finds devices by mDNS and talks to them over UDP, mostly IPv6. Nexus must run with host networking (network_mode: host, as in the provided compose.yaml); Docker's bridge network hides mDNS and IPv6 link-local addresses.

  • Same network segment. The Echo (or Google hub, Apple TV, Home Assistant) and the Nexus host must be in the same VLAN. mDNS does not cross VLANs unless a reflector (an mDNS repeater on the router) is set up, and even then Matter often fails.
  • IPv6. IPv6 must be enabled on the host's network interface. Link-local addresses (fe80::) are enough; no IPv6 from your provider is needed.
  • Ports. UDP 5540 (or the configured port) and UDP 5353 (mDNS) inbound on the host's firewall (ufw allow 5540/udp, ufw allow 5353/udp; in firewalld, the zone of that interface). The bridge shares port 5353 with avahi on the host; that is fine.
  • Wi-Fi. Some access points filter multicast between Wi-Fi and wired clients, or convert it ("multicast enhancement", "IGMP snooping" without a querier, "client isolation"). If the Echo is on Wi-Fi and pairing never finds the bridge, try turning those off.
  • Several Matter programs on one host (Home Assistant's Matter Server, Matterbridge, a second bridge instance) each need their own UDP port.

Troubleshooting

Symptom What to check
The instance doesn't start: "UDP port 5540 is in use" Another Matter program listens there; choose another UDP port.
The app searches and never finds the bridge Same VLAN? IPv6 on the host? Host networking? Firewall open for UDP 5353 and the port? Wi-Fi multicast filtering? Is the pairing window still open (the panel says so)?
"Device is unresponsive" in Alexa after it worked Nexus or the instance is stopped, or the host's address changed; the app reconnects once the bridge runs again. A device removed in Nexus may stay as an unresponsive one; remove it in the app.
A routine doesn't start Alexa starts routines on changes only; the state actuator must change (for a contact: off → on).
A command does nothing The bridge already showed that state, so no change was sent (see How values convert); wire the state actuator.
Stopping the instance takes 3 s, with "didn't close within 3 s" in the log A paired app (an Echo) doesn't answer, e.g. it is unplugged. The bridge waits at most 3 s for it, then writes what is pending and stops.

The instance log shows matter.js's lines prefixed matter.js:: its notices as info, its warnings and errors as warnings and errors, its info lines as debug. Its debug lines are not logged.

Storage and writes

Everything the plugin keeps is in the instance's store, so in Nexus's database: the pairing code (pairing), the devices (devices), matter.js's data (matter:bridge/<context>, one key per storage context) and the remembered states (state:<device id>). Nothing is written to files.

Fabrics, sessions, access control, commissioning data, endpoint numbers and the pairing code are written at once. Device states (the attributes matter.js stores, and the remembered states) are merged: changes within 1.5 s become one write per key, and a stop writes what is pending. A crash loses at most the last 1.5 s of device states, never a pairing.

Measured with the plugin's tests (store writes):

What Writes
First start with 4 devices 11
Pairing one app 16
10 on/off commands from an app 1
10 contact changes and 10 temperatures from Nexus 2
A blind reporting 20 positions within 2 s 2 (20 without merging)

Memory

One instance uses about 45–55 MB of JavaScript heap and adds about 180 MB (5 devices) to 230 MB (50 devices of all types) to the memory of the Nexus process (RSS), mostly matter.js itself and its own engine in the plugin's worker. The plugin asks for a heap limit of 256 MB (heapMb). On a small machine (1–2 GB) run a single instance; one bridge carries up to 50 devices.

Limits

What Limit
Devices per bridge 50 (Alexa's limit for one bridge)
Device and bridge names 32 bytes (letters like ä count twice), unique per bridge ignoring case
Pairing window 15 minutes once paired; 48 hours while not paired
Paired apps in practice a handful; each app is one Matter fabric
Device types the 35 above; garage doors and gates (Matter's newer closures), air purifiers, air conditioners, water heaters, pumps and appliances are not in this version

Security notes

  • While a pairing window is open, anyone on the same network who knows or guesses the code can pair and then switch the devices of this bridge. The window opens only while nothing is paired or after Open pairing window, and closes after 15 minutes.
  • The pairing code is shown only on the instance page and in the action's answer, to logged-in users; it is never written to the log.
  • Pairing keys live in Nexus's database and its encrypted backup. Restoring a backup on a second machine while the first one still runs puts two bridges with the same identity on the network; stop one of them.
  • Every paired app can switch every device of the bridge. Put devices that must not be switched by voice into no bridge, or only as sensors.
  • A door lock in the bridge can be locked by every paired app and anyone who can talk to them. Unlocking is refused unless Allow unlocking is on; with it on, an app's own protection (Alexa's voice code) is all that stands between a voice command and an open door. Wire the lock request to Loxone only where that is acceptable.

Development

npm run build -w @lox-nexus/plugin-matter-bridge   # dist/plugin.js (~6.5 MB) and dist/THIRD-PARTY-LICENSES.txt
node --conditions=@lox-nexus/source --import tsx --test "plugins/matter-bridge/src/**/*.test.ts"
  • @matter/main (matter.js) is pinned to exactly 0.18.0; an update is a deliberate step, together with the Matter controller plugin. The bundle is not minified (matter.js relies on class names), replaces matter.js's Bun SQLite driver with a stub, and lists the licenses of all bundled packages (matter.js: Apache-2.0) in dist/THIRD-PARTY-LICENSES.txt.
  • matter.js is configured in code: its storage is the plugin store (one store key per storage context, matter:<node>/<context path>, longer keys shortened with a hash), it has no file system, it doesn't trap process signals, and its log goes to the instance log without the ASCII-art QR code.
  • matter.js reads ~/.matter/config.json and MATTER_* settings when it is loaded, if they exist; Nexus creates neither, and a plugin worker's environment is empty. (Turning this off would need matter.js's Node.js configuration loaded before matter.js itself, which a bundle and the tests can't guarantee.)
  • The tests pair the bridge with a matter.js controller in the same process over UDP on free ports, with mDNS on the loopback interface (mdns.networkInterface = lo), so npm test doesn't announce test bridges to the LAN.