IKEA launches Matter devices 2026 - will we need a hub?

For information, I can confirm that the Ikea Bilresa dual button remote control is working with openHAB without the Dirigera hub. Paired with OH using Aqara M200 as TBR.

First draft: Pairing Matter over Thread devices (Ikea et al). Only HW needed; Conbee II or III

Hi just to clear things up, openHAB does not talk to a ā€œdongleā€ like z-wave or zigbee b/c matter is purely a IP based protocol (it prefers IPV6, but works over IPV4 as well).

Thread is a radio protocol (similar to zigbee), but is technically not related to matter. Its simply exists to provide IPV6 addresses to Thread devices and act as a gateway to your IP network for those devices (once connected, you can ping them like any other IPv4/IPV6 device). Again, even when they have an IP, matter is not yet involved (in fact it needs an IP first for matter then to talk to it). It also handles clustering and other thread related stuff, but thats all handled internally.

The thread border router software has one official implementation (afaik) , maintained by Google, open sourced, and really designed to run on single board systems for TBRs. So while you can attach a thread usb stick and try and run a TBR on say a Pi or other Linux machine, its not every common, almost everything out there uses a very cheap esp32 based SOC board to run the whole thing. Usb sticks are very uncommon, so i do not recommend this route.

Obviously thread and matter are related in that they are used together in 3 ways:

  1. Part of the onboarding process when using a mobile device which uses bluetooth first to provision thread credentials to the device, then uses matter to try and talk to it when connected.
  2. TBR act as the IP gateway for thread devices ( passing all IP traffic back and forth)
  3. Newer TBRs can also double as a Matter devices and expose the Matter 1.4+ TBR Clusters, which allows management of the TBR configs over Matter… this is all done over wifi/ethernet IP and has nothing to do with the thread side other then configuring the thread parameters. This is where the convergence starts to happen.

Yes, its all very confusing…

Interesting. By curiosity, what kind of config parameters will we be able to manage that way ?

I will try to add the Aqara hub to OH to see if these clusters are available, but I have a serious doubt it is Thread 1.4.

Yes, its all very confusing…

It is already complicated for us who are following that since many months with a certain interest with the technical aspects, I can’t imagine for a lambda user!

So we have support for these in our binding today, and at the time i added this, we were the only vendor yet to support it, but thats changing soon, at CES there were a number of products announced with TBR matter clusters in them, so they are coming.

There is still work todo here i"m sure (i need more time to play with this stuff), but the foundation is there and i’m using it today to manage my 2 TBRs. The real value, at least to me, is being able to manage multiple TBRs with the same config (operational data set) from one place. This allows multiple TBRs to participate in one logical network which is awesome.

Configuring TBR parameters in openHAB (esp32 TBR running the official matter chip build)

TBR actions

Unfortunately its not so much Thread 1.4 related, but Matter 1.4 related (unfortunate both projects have been releasing with the same version numbers, but no relation to each other). I’m 99% sure it does not include those TBR clusters, plus i don’t think it exposes itself as a matter device.

Matter Device: IKEA of Sweden BILRESA scroll wheel

FYI, 3 sets of 5+5+7 channels:


Question: DSL is still my preferred rule language, but I believe it is not possible to get hold of all the multiple entry payload from these Trigger channels?

Payload is in variable receivedEvent.

You need to install JSONPATH transformation and then you can retrieve the different information from the payload like that:

rule "Ikea Bilresa dual button"
when
	Channel "matter:node:openhab:16591968857120375732:1#switch-multipresscomplete" triggered or
	Channel "matter:node:openhab:16591968857120375732:2#switch-multipresscomplete" triggered
then
	val previousPosition  = transform("JSONPATH", "$.previousPosition", receivedEvent)
	val totalNumberOfPressesCounted  = transform("JSONPATH", "$.totalNumberOfPressesCounted", receivedEvent)
	logInfo("Rule","Trigger channel " + triggeringChannel + " with event " + receivedEvent + " previousPosition=" + previousPosition + " totalNumberOfPressesCounted=" + totalNumberOfPressesCounted)
end

Edit: take care, retrieved values are of type String (and not Number). Code updated.

2 Likes

Thanks. You proved AI wrong. Said it couldn’t be done .. :slight_smile:
Using AI in coding every day I’m not to worried about losing my job …

I have now integrated my Ikea proximity sensors with my openhab solution to control some lutron caseta lights. The scenario is that I want the lights to turn on when the proximity sensor detects somebody, set a timer for 10 mins and reset the timer each time the person moves. Any actions to turn on or off the lights via switches, pico remotes or automation or will cancel the timer.

Creating the things/items using an Apple TV as the MBR was really simple and worked first time. It seems to take a minute after entering the pairing code and finding in in the inbox to get the thing to be active, but after that it seems solid.

A couple of iterations with Gemini and I ended up with the following, which I think is pretty reusable and universal.

const { actions, items, rules, triggers } = require('openhab');

/**
 * Class to manage Motion-based lighting for a specific room.
 * Supports multiple motion sensors for a single light.
 */
class MotionLightingController {
  
  /**
   * @param {string} lightItemName - The name of the light switch Item
   * @param {string|string[]} motionSensors - A single sensor name OR an array of names (e.g. ["Sensor1", "Sensor2"])
   * @param {number} timeoutMinutes - How long to keep the light on
   */
  constructor(lightItemName, motionSensors, timeoutMinutes) {
    this.lightItemName = lightItemName;
    
    // Ensure motionSensors is always a list, even if a single string was passed
    this.motionSensors = Array.isArray(motionSensors) ? motionSensors : [motionSensors];
    
    this.timeoutMinutes = timeoutMinutes;
    
    // Instance-specific state
    this.timer = null;
    this.isAutomationAction = false;

    this.createRules();
    console.info(`Initialized Motion Controller for ${lightItemName} with sensors: [${this.motionSensors.join(", ")}]`);
  }

  createRules() {
    // -------------------------------------------------------------------------
    // Rule 1: Motion Detected (Any Sensor)
    // -------------------------------------------------------------------------
    rules.JSRule({
      name: `Motion Logic: ${this.lightItemName}`,
      description: `Auto-on and timer logic for ${this.lightItemName}`,
      
      // dynamically create a trigger for EVERY sensor in the list
      triggers: this.motionSensors.map(sensor => triggers.ItemStateChangeTrigger(sensor, 'ON')),
      
      execute: (event) => {
        const light = items.getItem(this.lightItemName);
        const triggeringSensor = event.itemName; // Which specific sensor saw motion?

        if (light.state === "OFF") {
          console.info(`Motion (${triggeringSensor}): Turning ${this.lightItemName} ON`);
          this.isAutomationAction = true;
          light.sendCommand("ON");
          this.startTimer(light);
        } 
        else if (light.state === "ON") {
          if (this.timer !== null) {
            console.info(`Motion (${triggeringSensor}): Extending timer for ${this.lightItemName}`);
            clearTimeout(this.timer);
            this.startTimer(light);
          } else {
            console.info(`Motion (${triggeringSensor}): Ignored (Manual Override Active)`);
          }
        }
      }
    });

    // -------------------------------------------------------------------------
    // Rule 2: Manual Switch Operation (Override)
    // -------------------------------------------------------------------------
    rules.JSRule({
      name: `Manual Override: ${this.lightItemName}`,
      description: `Cancels timer if ${this.lightItemName} is manually switched`,
      triggers: [triggers.ItemStateChangeTrigger(this.lightItemName)],
      execute: (event) => {
        if (this.isAutomationAction) {
          this.isAutomationAction = false;
          return;
        }

        if (this.timer !== null) {
          console.info(`Manual Override: Cancelling timer for ${this.lightItemName}`);
          clearTimeout(this.timer);
          this.timer = null;
        }
      }
    });
  }

  startTimer(lightItem) {
    this.timer = setTimeout(() => {
      console.info(`Timer Expired: Turning ${this.lightItemName} OFF`);
      this.isAutomationAction = true;
      lightItem.sendCommand("OFF");
      this.timer = null;
    }, this.timeoutMinutes * 60 * 1000);
  }
}

// =============================================================================
// INSTANCES
// =============================================================================

// 1. Single Sensor Example
new MotionLightingController("OfficeCeiling_SwitchState", "officeMotion", 10);
new MotionLightingController("MasterBath_SwitchState", "PrimaryBathMotion", 5);

// // 2. Multiple Sensors Example (Kitchen)
// // Use an Array [...] to list multiple sensors
// new MotionLightingController(
//     "Kitchen_Light", 
//     ["Kitchen_Motion_Ceiling", "Kitchen_Motion_Door", "Kitchen_Motion_Sink"], 
//     5
// );

// // 3. Multiple Sensors Example (Hallway)
// new MotionLightingController(
//     "Hallway_Dimmer",
//     ["Hallway_Motion_Upstairs", "Hallway_Motion_Downstairs"],
//     2
// );

Thanks for posting, just FYI the delay is due to Thread not have a lot of throughput (but is very reliable), so it takes a little bit for us to fully interview the node (its like 10x slower to interview then wifi).