Turning on a Light with JavaScript

I used Matter’s open-source JavaScript code to control a light with a Raspberry Pi (RPi) and the Google Home app. This is part 1 of a series on home automation with Matter.

Paul Otto
13 min readSep 3, 2024
image by artist fiolisaviy

Overview

Matter is a secure communication protocol for interoperability among smart home products and IoT devices from companies like Google, Apple, and Amazon and you. It aims to simplify the integration of diverse devices into a unified home automation system. Open systems such as Home Assistant also support Matter. Matter enables:

  • Smart homes: Integrates a variety of devices such as door and window sensors, motion sensors, and environmental controls from multiple manufacturers.
  • Energy management: Reduces energy use with smart metering and light and HVAC control.
  • Commercial building management: Enhances operations and maintenance in commercial properties through the use of access control devices, automated lighting, environmental sensors, and controls.

Matter operates by passing messages between devices that have “Nodes” in the same security domain. Nodes are the addressable entities that support the Matter protocol stack. The messages are sent between these addressable Nodes on the devices. The logical collection of communicating Nodes, sharing a common root of trust, and a common distributed configuration state is called the Fabric. The Fabric can be thought of as a security domain with a cryptographical root which all the Nodes share so they can interoperate securely with each other. Matter is an open standard available for download and source code available on GitHub. One of the Matter source code repositories is an implementation in JavaScript called Matter.js. This implementation is great for prototyping OS-based IoT products and for smart home enthusiasts (me).

Note: In Matter a device is defined as “A piece of equipment containing one or more Nodes.” Often and for this article there is only one Node running on the equipment hardware, but this is not a restriction and there could be multiple Nodes running on the device.

This article will document my journey setting up Matter.js on a Raspberry Pi as a light on the Matter Fabric formed by a Google Nest Mini. I will test the setup using the Google Home App to turn on and off a light and share some Matter I learned along the way.

Wi-Fi troubleshooting tip: Disable AP Isolation

Before setting up Matter I want to share two lessons I learned the hard way.

First, the Wi-Fi must have Internet access if using a Google Nest Mini. This is not a requirement for Matter in general.

Second, the Wi-Fi network should not have AP Isolation turned on. AP Isolation also known as Station Isolation, or Client Isolation is a security feature to prevent device to device communication on same network. A main goal of the feature is to stop the spread of malware between devices. This security feature is common on public Wi-Fi’s and guest networks, but not common on home networks where devices such as printers need to be accessed by other devices. AP Isolation is also a problem with Matter because the devices need to communicate with each other. I found that if I had to use a guest network I could connect with a travel router (I used a TP-Link AC750 Travel Router) and then have the Google Nest Mini, phone with the Google Home App, and Raspberry Pi all connect to the travel router. I also tried to hotspot my Android phone which worked, but my iPhone did not. My guess is the iPhone has AP isolation enabled.

Setup the Raspberry Pi with Matter.js

Running a Matter device on the Raspberry Pi can be done by using the Matter.js source code repository directly or including the compiled code as a package. I chose the first option because the Matter.js code repository includes useful examples, and it allowed me to modify the code so that I can log extra information to analyze the Matter message communication.

The steps to setup the Raspberry Pi are:

  1. Setup Raspberry Pi and configure it. This involves setting up the Raspberry Pi hardware and OS and configure the Raspberry Pi to connect to the Wi-Fi network which must run IPv6 locally. It is not necessary to have IPv6 Internet access since Matter is a local protocol. Optional: if you are planning on using the Ansible script I describe below, then allow SSH connections in the OS customization step.
  2. Setup needed tools to compile the Matter.js code. These tools are Git, Python, NodeJS, and NPM. This can be done manually but I will use an Ansible script.
  3. Clone the Matter.js repo and build it.

Here are details for the above steps.

Setup Raspberry Pi and configure it with Matter.js.

I followed the official instructions for a Raspberry Pi 4 with 128 GB SD card. I also entered in my Wi-Fi information at this time and setup SSH to be active from the options tab. The Raspberry Pi needs to already be on the Wi-Fi network for this example, although there is a way to add it using the Bluetooth to configure the Wi-Fi network.

The Raspberry Pi setup with light in the on state is shown in Figure 1. I connected a relay board from Waveshare to control the light (Fig. 1D). To keep it simple and safe I have a relay turn on a set of light emitting diodes (LEDs) that are connected in parallel with individual resistors to limit their current (Fig. 1B). The LEDs are powered by a USB battery (Fig. 1A). Details on the electrical design are in the appendix at the end of the article. The Google Home App is used to turn on the light (Fig. 1C). An unrelated and interesting part of Figure 1 is the lens artifact showing the two LEDs in the upper right part of the image. This is a useful way to look at the detail of a very bright object. The YouTuber MinutePhysics has a good video explaining the artifact.

Figure 1: Raspberry Pi setup with light in the on state. (A) five-volt USB battery with USB A interface (B) Lighting circuitry composed of two LEDs (C) The Google Home App used to turn on the light (D) The Raspberry Pi (RPi) with a three-relay expansion board. The bottom relay is being used for control

After booting up the Raspberry Pi and verifying I could SSH to the board I used Ansible scripts in the automation repo to setup the dependency environment for Matter.js and clone the code repository.

In the automation repo README.md I followed the setup instructions and then the section To setup a Matter.js on the device matter_js_test to run the two playbooks which are shown below.

# First install the general communication development environment playbook to setup python and vim 
ansible-playbook -vv ./playbooks/setup_general_comm_dev.yaml --vault-password-file ./vault/vault_password.txt -l matter_js_test --extra-vars "install_python=true python_version=3.12.5"
# Now setup matter.js and its dependencies
ansible-playbook -vv ./playbooks/install_matter.yaml --vault-password-file ./vault/vault_password.txt -l matter_js_test --extra-vars "install_nodejs=true install_matterjs=true"

I SSHed into the Raspberry Pi and created a script (minor modifications to a Waveshare script) to control the relays with the GPIO pins using the program pinctrl. I created the script relay.sh in my user home directory and made it executable with chmod +x relay.sh The code for the script is:

#!/bin/bash

# Examples to turn on and off the 3 relays different
# ./relay.sh CH1 ON
# ./relay.sh CH2 ON
# ./relay.sh CH3 OFF

# Validate and set channel based on first argument
if [ "$1" == 'CH1' ]; then
ch=26
elif [ "$1" == 'CH2' ]; then
ch=20
elif [ "$1" == 'CH3' ]; then
ch=21
else
echo "Parameter error"
exit 1
fi

# Validate and set state based on second argument
if [ "$2" == 'ON' ]; then
state='dh' # Drive High
elif [ "$2" == 'OFF' ]; then
state='dl' # Drive Low
else
echo "Parameter error"
exit 1
fi

# Set GPIO to output, no pull, and define state (High or Low)
pinctrl set $ch op pn $state

# Optionally, echo back the new pin states
pinctrl -e get $ch

echo "relay $1 set to $2"

I then built and ran the socket example in Matter.js.

# navigate to the Matetr.js repo
cd ~/matter/matter.js
# build Matter.js and run the switch example
npm install
npm run matter-device -- -type socket --on="/home/user/relay.sh CH1 OFF" --off="/home/user/relay.sh CH1 ON" -loglevel debug

When running the code for the first time you should see a QR code appear (Fig. 2) and this is what will be scanned by the Google Home App in a later step.

Figure 2: The QR code used for commissioning

Now it is time to setup the Matter Fabric.

Setup the Matter Fabric with the Google Nest Mini and the Google Home App

I used the Google Nest Mini as my hub to set up the Matter Fabric, which I configured via the Google Home App using this tutorial. I chose the Google Nest Mini because it is low cost and operates over Wi-Fi which simplifies connectivity for this project. The Google Nest Mini does not support the 802.15.4 Thread protocol which is required by some Matter devices.

The Fabric allows each devices’ Nodes to communicate and share information with other devices. The integration of a Node into the Fabric, is known as “commissioning.” This process starts with device discovery. A key technology in this process is the Multicast Domain Name Service (mDNS), which is essential for discovering devices and managing their commissioning within the network. For those interested in a deeper dive into how mDNS functions within Matter, I have detailed it further in a separate article.

Nodes consist of multiple “Endpoints.” Each Endpoint has a specific feature set; for example, one might handle lighting control, another motion detection, and another utilities such as Device OTA (Over-The-Air updates). Each node can assume one or more roles based on its functionality within the Fabric:

  • Commissioner: A node that facilitates the commissioning of other nodes into the Fabric. Commissioners can run on a variety of platforms or devices, including phone, smart speakers, or displays. These devices may serve exclusively as Commissioners or may also perform additional roles such as Administrator or Controller within the network.
  • Controller: A node capable of controlling one or more other nodes. Examples include the Google Home app, Google Assistant, and devices running on the Google Nest Mini.
  • Controlee: A node that can be controlled by one or more nodes. Most device types, including the Matter.js example program running on the Raspberry Pi in our setup, can serve as Controlees. This configuration allows the Raspberry Pi to be managed via external controls, such as an On/Off Light Switch. Certain devices, including the On/Off Light Switch, are exclusively Controllers and do not have the functionality to act as Controlees. In our scenario, the phone running the Google Home app acts as such a Controller, effectively turning the On/Off Light Switch on or off and thereby controlling the device running on the Raspberry Pi.

With the Matter Fabric established using the Google Nest Mini and Google Home App, the next step involves integrating the node on the Raspberry Pi into this Fabric through the commissioning process.

Commissioning a node on the Raspberry Pi onto the Matter Network

Matter defines “commissioning” as the “Sequence of operations to bring a Node into a Fabric by assigning an Operational Node ID and Node Operational credentials”.

To integrate the node of the device (the Matter.js program) running on the Raspberry Pi into the home automation setup, I commissioned it onto the Matter Fabric using Wi-Fi. Although commissioning can also be conducted over Bluetooth, using only Wi-Fi simplified the RPi’s setup.

The Google Home App on a smartphone will act as the Matter Commissioner. The commissioning process involves several critical steps:

  • Authentication: The Commissioner verifies the authenticity of the device being added to ensure it is a legitimate and secure component of the Fabric.
  • Fabric Credential Assignment: Once authenticated, the Commissioner assigns necessary credentials to the new device, enabling it to communicate within the Matter Fabric.

The commissioning of the device on the Raspberry Pi (Fig. 3) starts when the Google Home App, scans a QR code (Fig. 2) generated by the Raspberry Pi. This QR code is a secure method to ensure that only authorized devices can join the Matter Fabric. The Google Home App will warn that this is a “uncertified device” and ask if you want to setup anyway. This is because we are experimenting with the source code and we have not gone through the Matter certification process to have the proper credentials. To avoid the message see this note.

Troubleshooting Tip: If the commissioning process fails, it may be due to a timeout issue of the device on the Raspberry Pi. In such cases, restarting the Matter.js program on the Raspberry Pi and rescanning the QR code can often resolve the problem. Also to start fresh you can remove the ~./matter directory.

With the Raspberry Pi device successfully commissioned and now part of the Matter network, we are set to explore its functionalities in controlling smart devices. The next step is to control a light with the Raspberry Pi.

Figure 3: The relationship between devices on the Matter Fabric. The Controller QR code that the phone needs to scan is created by a device program running on the Raspberry Pi

Controlling the light with the Raspberry Pi using Matter

With the Raspberry Pi’s device node successfully commissioned onto the Matter network, it’s ready to be controlled via the Google Home App. Now it’s time to discuss Matter clusters and their roles in device interactions, in particular the On/Off Switch cluster.

Nodes are composed of endpoints which are composed of clusters. Clusters represent collections of attributes and commands specific to functionalities of devices. For example, the On/Off Server Cluster is running on the Raspberry Pi and is responsible for managing the physical state (on or off) of a device, such as the LEDs connected to the Raspberry Pi. It is controlled by the On/Off Client Cluster running on the Google Home App. The Client Cluster sends commands that alter the state of the Server Cluster, for example by turning the light on or off.

This interaction is governed by the Matter Interaction Model, which defines how Attributes (properties like the current state of a light) and Commands (actions such as turning a light on or off) operate within clusters. Commands in Matter can be likened to remote procedure calls, with the capability to generate responsive actions or results, which are also framed as Commands but in a reverse direction. Matter provides a lot of flexibility with turning devices on or off and this will be examined in future articles.

The operations of these clusters and their interactions can be analyzed in real-time using tools such as Teledyne LeCroy wireless protocol analyzer to capture the wireless traffic and Teledyne LeCroy’s Wireless Protocol Suite (WPS) to analyze the captured traffic. For instance, Matter packets transmitted over the air can be captured and dissected in WPS to understand the dynamics of command exchanges and attribute changes within the network. For example, Figure 4 shows the Wi-Fi Matter packet captured when the light was turned on.

Figure 4: Controlling the light with the Google Home App causes Matter over the air traffic to be sent.

Conclusion

I’ve only scratched the surface of what’s possible with Matter. This journey has introduced the basic constructs of the Matter protocol — nodes, endpoints, and clusters — and how they interact to create a seamless and secure smart home environment. However, there remains a number of interesting areas to explore such as:

  • Analyzing over-the-air packets to understand the commissioning process and the day-to-day operations of Matter-enabled devices.
  • Automating the Raspberry Pi to start up running Matter.js with systemctl.
  • Explorer other Matter.js examples such as integrating sensors and performing Bluetooth-based commissioning.
  • Use theMatter.js package in a custom application. This can be first investigated by installing the matter-node.js-examples npm package
  • Experiment with automation rules using the Raspberry Pi and other Matter devices in a Matter Controller like the Google Home app or Nest.

There are a lot of exciting things to do with Matter.js, what would you like to do?

Appendix 1: Electrical setup of relay with light

In the circuit I have a relay (Fig. 5 S1) to turn on a set of LEDs that are connected in parallel with individual resistors to limit their current. The power is from a USB battery (Fig 5. V1), and I am keeping the current draw high enough to prevent the battery from turning off. Unfortunately, I bought the LEDs in bulk and I don’t have the part number or datasheet. When testing I found they consume 47 milliamps of current at 2.6 volts. Therefore, when connected to the USB battery (Fig 5. V1) I used a 51-ohm resistor to drop the remaining 2.4 V of the 5V battery. I found if I used one LED then the USB battery would shut off after a minute which I assume is due to the battery thinking the device charge cycle is complete. Using two LEDs in parallel doubled the current draw to 94 milliamps and kept the battery on continuously. I added a 10-killiohm resistor (Fig 5. R3) to the circuit so the battery will initally turn on. Without it the resistance of the LED in the off state must be too high to trigger the battery to turn on.

Figure 5: Lighting circuit implementation with the schematic

I have separate resistors for each LED because connecting the LEDs in parallel to a single resistor can lead to two problems.

First, thermal runaway. If one LED in a parallel circuit starts to draw more current (due to lower forward voltage), it will heat up more. As the temperature of an LED increases, its forward voltage typically decreases, causing it to draw even more current. This can lead to a positive feedback loop known as thermal runaway, where the LED draws too much current, gets hotter, and eventually fails. Because a single resistor for all LEDs is designed for their maximum current draw this would allow the single LED to draw significant current as its resistance decreases.

Second, a LED can burnout prematurely because of LEDs have slightly different forward voltage drops, even if they are of the same type. When connected in parallel to a single resistor, the LED with the lowest forward voltage drop will draw more current than the others, leading to an imbalance. This can cause the LED drawing more current to overheat and potentially burn out prematurely. Individual resistors allow adjustment of this.

--

--

Paul Otto

I enjoy exploring the full wireless stack and experimenting with embedded Rust. I'm often hanging out at the Charlottesville Rust Meetup.