A Thread border router is not mandatory to interact with Matter devices
Matter is a “super-standard” for IoT device interoperability: it promotes cooperation between smart things manufacturers and allows to control objects from the local network. It is relatively new, as its first specification version just came out in 2022.
Even if the ability to get devices into market requires an attestation from Matter consortium, it is possible to study how Matter works at a relatively cheap cost.
Matter works over IP-based technologies like Wi-Fi (“Matter-over-WiFi”) and Thread (“Matter-over-Thread”). While the first is generally used for the communication with devices transferring large amount of data (e.g. cameras), the latter is suitable for low-power devices requiring to transfer small amount of data (e.g. sensors or lights).
Matter-over-Thread guarantees communications among a variety of devices and networks and to do so it requires two special “components”: a Thread border Router and a Radio Controller. The Thread Border Router handles communications among different kind of networks (eg. Wi-Fi, Ethernet and Thread) while the Radio Controller handles communication among devices.
How does Matter work
Adding a device to a network with Matter is super-easy: just scan its QR code and that’s it, the device is ready and configured. But what’s in that QR code?
The QR code contains a lot of informations used to integrate the device into the domestic network such as the version of Matter standard, PIN and passkey to authenticate the device in the configuration phase, informations about the device and its vendor - namely the Vendor ID (VID) and Product ID (PID) – and security certifications of conformity to the CSA standard.
In order to produce Matter devices, manufacturers must register to the Connectivity Standard Alliance (CSA), which manages the Matter protocol. It’s CSA to assign the VID to uniquely identify each manufacturer and then each manufacturer uniquely assign PID to its own devices (and so, the union of VID and PID uniquely identify the device). This ensures interoperability and guarantees that a device is coming from a verified manufacturer and that it respects the Matter standard.
When the user scans the QR code (e.g. in the Google Home application on the phone), a pairing is initiated using PIN and informations stored in the QR code itself and the authentication certifies that the device is legitimate. The app also connects the device to the Wi-Fi network or the Thread network and when the pairing is completed, the device is part of the network, being accessible from all the other compatible devices and controllers.
CSA also gives a generic VID for test and development purposes only so that developers can test Matter devices without a formal certification at no cost (and of course, that generic VID cannot be used for commercial products!)
Adding a device to the network: the commissioning
The process of registering and adding a Matter device to a network is called commissioning.
When the user wants to add a new device to network, the Google Home app (or another app capable to add Matter compatible devices) will act as commissioner. It will ask the user to scan the QR code (or to enter a PIN) printed on the device: at this point, the device is temporarily connected to the commissioner, cryptographic keys are exchanged to secure operational connection, informations to join the network are received and and the device is officially part of the network.
Removing a device from the network: the decommissioning
Conversely, the process of removing a Matter device from the network is called decommissioning: it can be requested with an app (e.g. Google Home App) or from the device itself (e.g. pressing a button).
When the device is decommissioned, cryptographic keys are invalidated and the device is reset. At this point the device cannot communicate anymore with the other devices in the network.
A low cost “hands-on” experiment with ESP32
One way to play with Matter on a board without having to buy or configure a Thread border router is using an ESP32: Arduino core for ESP32 in fact gives us the capability to use Arduino IDE and the Arduino framework to deploy a Matter-enabled board.
After installing ESP32 support in ArduinoIDE, just compile and upload the following example to the board (it has been readapted from example script in Arduino-esp32 repository from Espressif):
// Matter Manager | |
#include "secrets.h" | |
#include <Matter.h> | |
#include <WiFi.h> | |
#include <Preferences.h> | |
// WiFi is manually set and started | |
const char *ssid = YOUR_SSID; // Change this to your WiFi SSID | |
const char *password = YOUR_PASSWORD; // Change this to your WiFi password | |
// List of Matter Endpoints for this Node | |
// On/Off Light Endpoint | |
MatterOnOffLight OnOffLight; | |
// it will keep last OnOff state stored, using Preferences | |
Preferences matterPref; | |
const char *onOffPrefKey = "OnOff"; | |
// set your board LED pin here | |
const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN | |
// set your board USER BUTTON pin here | |
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. | |
// Button control | |
uint32_t button_time_stamp = 0; // debouncing control | |
bool button_state = false; // false = released | true = pressed | |
const uint32_t debouceTime = 250; // button debouncing time (ms) | |
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission | |
// Matter Protocol Endpoint Callback | |
bool setLightOnOff(bool state) { | |
Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); | |
if (state) { | |
digitalWrite(ledPin, HIGH); | |
} else { | |
digitalWrite(ledPin, LOW); | |
} | |
// store last OnOff state for when the Light is restarted / power goes off | |
matterPref.putBool(onOffPrefKey, state); | |
// This callback must return the success state to Matter core | |
return true; | |
} | |
void setup() { | |
// Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch | |
pinMode(buttonPin, INPUT_PULLUP); | |
// Initialize the LED (light) GPIO and Matter End Point | |
pinMode(ledPin, OUTPUT); | |
Serial.begin(115200); | |
// We start by connecting to a WiFi network | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
// Manually connect to WiFi | |
WiFi.begin(ssid, password); | |
// Wait for connection | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println("\r\nWiFi connected"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
delay(500); | |
// Initialize Matter EndPoint | |
matterPref.begin("MatterPrefs", false); | |
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); | |
OnOffLight.begin(lastOnOffState); | |
OnOffLight.onChange(setLightOnOff); | |
// Matter beginning - Last step, after all EndPoints are initialized | |
Matter.begin(); | |
// This may be a restart of a already commissioned Matter accessory | |
if (Matter.isDeviceCommissioned()) { | |
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); | |
Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); | |
OnOffLight.updateAccessory(); // configure the Light based on initial state | |
} | |
} | |
void loop() { | |
// Check Matter Light Commissioning state, which may change during execution of loop() | |
if (!Matter.isDeviceCommissioned()) { | |
Serial.println(""); | |
Serial.println("Matter Node is not commissioned yet."); | |
Serial.println("Initiate the device discovery in your Matter environment."); | |
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); | |
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); | |
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); | |
// waits for Matter Light Commissioning. | |
uint32_t timeCount = 0; | |
while (!Matter.isDeviceCommissioned()) { | |
delay(100); | |
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec | |
Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); | |
} | |
} | |
Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); | |
OnOffLight.updateAccessory(); // configure the Light based on initial state | |
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); | |
} | |
// A button is also used to control the light | |
// Check if the button has been pressed | |
if (digitalRead(buttonPin) == LOW && !button_state) { | |
// deals with button debouncing | |
button_time_stamp = millis(); // record the time while the button is pressed. | |
button_state = true; // pressed. | |
} | |
// Onboard User Button is used as a Light toggle switch or to decommission it | |
uint32_t time_diff = millis() - button_time_stamp; | |
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) { | |
button_state = false; // released | |
// Toggle button is released - toggle the light | |
Serial.println("User button released. Toggling Light!"); | |
OnOffLight.toggle(); // Matter Controller also can see the change | |
} | |
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node | |
if (button_state && time_diff > decommissioningTimeout) { | |
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); | |
OnOffLight.setOnOff(false); // turn the light off | |
Matter.decommission(); | |
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so | |
} | |
} |
In the snippet of code, the class of the device configures all the callable methods for the object and callbacks it responds to. In this case, since the board acts as a switch light:
MatterOnOffLight OnOffLight;
…
OnOffLight.toggle();
OnOffLight.onChange(setLightOnOff);
Also note:
OnOffLight.updateAccessory();
This directive ensures that the current state of the light (e.g., whether it is ON or OFF) is correctly reflected on the device and on the controller. This could be useful if, for example, the user presses a button to toggle the light state: updateAccessory() would reflect that change in the Google Home App. Conversely, if the user toggle the light from the application, updateAccessory() would update device state accordingly.
If you want to upload the snippet to ESP32, make sure to set the partition scheme to “Minimal SPIFFS”, to gain some space for the code.
Now it's time to add the device to the local network by choosing to add a "Matter enabled device":
and to enter the pin to begin the commissioning process (the pin is written in the serial output by the sketch, you can also scan the QR code at given the url):
Once the process ends (you should receive a message about the board not being certified but in this case is related to the fact that is just a development device) the board joined network!
In the following video you can see the results of the experiment: the board is controlled from the Google Home mobile application. On the converse, a button on the board also acts as a "switch" lighting or shutting off the led and the status on the mobile app gets updated using Matter protocol.
Top comments (1)
Great share @antigones I got to know about matter support on ESP32, and it's google home compilation.