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 incompose.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.
typeis the kind, and the type goes in the kind's own field:Kind ( type)Field Types Light ( lights)lightdimmable-light,on-off-light,color-temperature-light,color-lightPlug ( plugs)plugplug,dimmable-plugWall switch or dimmer ( wall-controls)wallControlwall-switch,wall-dimmerBlind or shutter ( blinds)blindwindow-covering,venetian-blindThermostat ( thermostats)thermostatthermostat,thermostat-heat-coolSensor ( sensors)sensortemperature-sensor,humidity-sensor,light-sensor,pressure-sensor,flow-sensor,air-quality-sensorLeak, rain or frost sensor ( water-sensors)waterSensorwater-leak-detector,rain-sensor,water-freeze-detectorButton or doorbell ( buttons)buttongeneric-switch,doorbellEnergy meter ( energy-meters)energyMeterelectrical-meter,solar-power,battery-storageEvery 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,typewas 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 exactly0.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) indist/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.jsonandMATTER_*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), sonpm testdoesn't announce test bridges to the LAN.