[Matter] Add a device's power consumption

Following the request from @jmarandet to manage his Shelly ( Aide pour connexion Shelly EM avec Gladys en MQTT - #8 par jmarandet ), add management of power consumption and the following Matter clusters:

"id": "156",
"name": "PowerTopology",
"id": "144",
"name": "ElectricalPowerMeasurement",
"id": "145",
"name": "ElectricalEnergyMeasurement",

Hello everyone :slight_smile:

I created a PR on this topic, completely blind, based on what I found in Matter.js.

@Nagromdark Can you take a look at the PR and tell me what you think? If you have any hardware to test with, I’m up for it too :smiley:

@jmarandet I

1 Like

Hi, I haven’t looked yet, I have a bit less time at the moment. I don’t have a device to test this anyway, sorry

1 Like

I set up a small test environment with my Eve Energy plug that reports consumption, but I’m going crazy — I managed to get the voltage, current, and power, but I can’t get the energy meter reading:

Because the meter reading is only reported every 10 minutes, testing is very time-consuming — I’ve been on it for an hour and a half :joy:

Ok, I’ve talked quite a bit with the developer of Matter.js, and it’s probably related to my Eve Energy plug that doesn’t seem to be reporting the cumulative consumption value.

I tested with Matterbridge and matterbridge-example-dynamic-platform but it still doesn’t work either, the value isn’t being sent…

I’m a bit stuck when it comes to test hardware :sweat_smile:

Hi everyone,

Unfortunately I couldn’t test it, but to move things forward I’ve deployed this development in Gladys Assistant 4.65, it will be easier to get feedback.

I’d appreciate any feedback to let me know whether it works or not :slight_smile:

cc @jmarandet

Salut @pierre-gilles,

Chez moi cela ne fonctionne pas. J’ai une prise Nous A8M https://www.domadoo.fr/fr/devices-matter/7147-nous-prise-connectee-wifi-matter-16a-mesure-consommation-a8m.html avec mesure de consommation mais je n’ai pas de remonté dans Gladys.

Voici une capture de l’app de la prise ou j’ai ici une conso de 25w. Donc la mesure est OK

Côté Gladys j’ai que la fonctionnalité Commutateur

Toutes les fonctionnalitées disponibles sont dans le json ?

Si j’essai de comprendre pourquoi je doit pouvoir retrouver une des fonctionnalités que tu as ajouté?

image

Ci dessous le json

{
    "node_id": "15556639130473728473",
    "is_connected": true,
    "devices": [
      {
        "name": "MA-onoffpluginunit",
        "number": "1",
        "cluster_clients": [
          {
            "id": "3",
            "name": "Identify",
            "attributes": [
              "0",
              "1",
              "65528",
              "65529",
              "65531",
              "65532",
              "65533",
              "identifyTime",
              "identifyType",
              "clusterRevision",
              "featureMap",
              "attributeList",
              "acceptedCommandList",
              "generatedCommandList"
            ],
            "commands": [
              "0",
              "64",
              "identify",
              "triggerEffect"
            ],
            "all_keys": [
              "id",
              "name",
              "revision",
              "_type",
              "supportedFeatures",
              "isUnknown",
              "endpointId",
              "attributes",
              "events",
              "commands",
              "subscribeAllAttributes",
              "_triggerAttributeUpdate",
              "_triggerEventUpdate",
              "isAttributeSupported",
              "isAttributeSupportedByName",
              "isCommandSupported",
              "isCommandSupportedByName",
              "getIdentifyTimeAttribute",
              "setIdentifyTimeAttribute",
              "subscribeIdentifyTimeAttribute",
              "addIdentifyTimeAttributeListener",
              "removeIdentifyTimeAttributeListener",
              "getIdentifyTypeAttribute",
              "setIdentifyTypeAttribute",
              "subscribeIdentifyTypeAttribute",
              "addIdentifyTypeAttributeListener",
              "removeIdentifyTypeAttributeListener",
              "getClusterRevisionAttribute",
              "setClusterRevisionAttribute",
              "subscribeClusterRevisionAttribute",
              "addClusterRevisionAttributeListener",
              "removeClusterRevisionAttributeListener",
              "getFeatureMapAttribute",
              "setFeatureMapAttribute",
              "subscribeFeatureMapAttribute",
              "addFeatureMapAttributeListener",
              "removeFeatureMapAttributeListener",
              "getAttributeListAttribute",
              "setAttributeListAttribute",
              "subscribeAttributeListAttribute",
              "addAttributeListAttributeListener",
              "removeAttributeListAttributeListener",
              "getAcceptedCommandListAttribute",
              "setAcceptedCommandListAttribute",
              "subscribeAcceptedCommandListAttribute",
              "addAcceptedCommandListAttributeListener",
              "removeAcceptedCommandListAttributeListener",
              "getGeneratedCommandListAttribute",
              "setGeneratedCommandListAttribute",
              "subscribeGeneratedCommandListAttribute",
              "addGeneratedCommandListAttributeListener",
              "removeGeneratedCommandListAttributeListener",
              "identify",
              "triggerEffect"
            ]
          },
          {
            "id": "4",
            "name": "Groups",
            "attributes": [
              "0",
              "65528",
              "65529",
              "65531",
              "65532",
              "65533",
              "nameSupport",
              "clusterRevision",
              "featureMap",
              "attributeList",
              "acceptedCommandList",
              "generatedCommandList"
            ],
            "commands": [
              "0",
              "1",
              "2",
              "3",
              "4",
              "5",
              "addGroup",
              "viewGroup",
              "getGroupMembership",
              "removeGroup",
              "removeAllGroups",
              "addGroupIfIdentifying"
            ],
            "all_keys": [
              "id",
              "name",
              "revision",
              "_type",
              "supportedFeatures",
              "isUnknown",
              "endpointId",
              "attributes",
              "events",
              "commands",
              "subscribeAllAttributes",
              "_triggerAttributeUpdate",
              "_triggerEventUpdate",
              "isAttributeSupported",
              "isAttributeSupportedByName",
              "isCommandSupported",
              "isCommandSupportedByName",
              "getNameSupportAttribute",
              "setNameSupportAttribute",
              "subscribeNameSupportAttribute",
              "addNameSupportAttributeListener",
              "removeNameSupportAttributeListener",
              "getClusterRevisionAttribute",
              "setClusterRevisionAttribute",
              "subscribeClusterRevisionAttribute",
              "addClusterRevisionAttributeListener",
              "removeClusterRevisionAttributeListener",
              "getFeatureMapAttribute",
              "setFeatureMapAttribute",
              "subscribeFeatureMapAttribute",
              "addFeatureMapAttributeListener",
              "removeFeatureMapAttributeListener",
              "getAttributeListAttribute",
              "setAttributeListAttribute",
              "subscribeAttributeListAttribute",
              "addAttributeListAttributeListener",
              "removeAttributeListAttributeListener",
              "getAcceptedCommandListAttribute",
              "setAcceptedCommandListAttribute",
              "subscribeAcceptedCommandListAttribute",
              "addAcceptedCommandListAttributeListener",
              "removeAcceptedCommandListAttributeListener",
              "getGeneratedCommandListAttribute",
              "setGeneratedCommandListAttribute",
              "subscribeGeneratedCommandListAttribute",
              "addGeneratedCommandListAttributeListener",
              "removeGeneratedCommandListAttributeListener",
              "addGroup",
              "viewGroup",
              "getGroupMembership",
              "removeGroup",
              "removeAllGroups",
              "addGroupIfIdentifying"
            ]
          },
          {
            "id": "6",
            "name": "OnOff",
            "attributes": [
              "0",
              "16384",
              "16385",
              "16386",
              "16387",
              "65528",
              "65529",
              "65531",
              "65532",
              "65533",
              "onOff",
              "clusterRevision",
              "featureMap",
              "attributeList",
              "acceptedCommandList",
              "generatedCommandList",
              "globalSceneControl",
              "onTime",
              "offWaitTime",
              "startUpOnOff"
            ],
            "commands": [
              "0",
              "1",
              "2",
              "64",
              "65",
              "66",
              "off",
              "on",
              "toggle",
              "offWithEffect",
              "onWithRecallGlobalScene",
              "onWithTimedOff"
            ],
            "all_keys": [
              "id",
              "name",
              "revision",
              "_type",
              "supportedFeatures",
              "isUnknown",
              "endpointId",
              "attributes",
              "events",
              "commands",
              "subscribeAllAttributes",
              "_triggerAttributeUpdate",
              "_triggerEventUpdate",
              "isAttributeSupported",
              "isAttributeSupportedByName",
              "isCommandSupported",
              "isCommandSupportedByName",
              "getOnOffAttribute",
              "setOnOffAttribute",
              "subscribeOnOffAttribute",
              "addOnOffAttributeListener",
              "removeOnOffAttributeListener",
              "getClusterRevisionAttribute",
              "setClusterRevisionAttribute",
              "subscribeClusterRevisionAttribute",
              "addClusterRevisionAttributeListener",
              "removeClusterRevisionAttributeListener",
              "getFeatureMapAttribute",
              "setFeatureMapAttribute",
              "subscribeFeatureMapAttribute",
              "addFeatureMapAttributeListener",
              "removeFeatureMapAttributeListener",
              "getAttributeListAttribute",
              "setAttributeListAttribute",
              "subscribeAttributeListAttribute",
              "addAttributeListAttributeListener",
              "removeAttributeListAttributeListener",
              "getAcceptedCommandListAttribute",
              "setAcceptedCommandListAttribute",
              "subscribeAcceptedCommandListAttribute",
              "addAcceptedCommandListAttributeListener",
              "removeAcceptedCommandListAttributeListener",
              "getGeneratedCommandListAttribute",
              "setGeneratedCommandListAttribute",
              "subscribeGeneratedCommandListAttribute",
              "addGeneratedCommandListAttributeListener",
              "removeGeneratedCommandListAttributeListener",
              "getGlobalSceneControlAttribute",
              "setGlobalSceneControlAttribute",
              "subscribeGlobalSceneControlAttribute",
              "addGlobalSceneControlAttributeListener",
              "removeGlobalSceneControlAttributeListener",
              "getOnTimeAttribute",
              "setOnTimeAttribute",
              "subscribeOnTimeAttribute",
              "addOnTimeAttributeListener",
              "removeOnTimeAttributeListener",
              "getOffWaitTimeAttribute",
              "setOffWaitTimeAttribute",
              "subscribeOffWaitTimeAttribute",
              "addOffWaitTimeAttributeListener",
              "removeOffWaitTimeAttributeListener",
              "getStartUpOnOffAttribute",
              "setStartUpOnOffAttribute",
              "subscribeStartUpOnOffAttribute",
              "addStartUpOnOffAttributeListener",
              "removeStartUpOnOffAttributeListener",
              "off",
              "on",
              "toggle",
              "offWithEffect",
              "onWithRecallGlobalScene",
              "onWithTimedOff"
            ]
          },
          {
            "id": "29",
            "name": "Descriptor",
            "attributes": [
              "0",
              "1",
              "2",
              "3",
              "4",
              "65528",
              "65529",
              "65531",
              "65532",
              "65533",
              "deviceTypeList",
              "serverList",
              "clientList",
              "partsList",
              "clusterRevision",
              "featureMap",
              "attributeList",
              "acceptedCommandList",
              "generatedCommandList",
              "tagList"
            ],
            "commands": [],
            "all_keys": [
              "id",
              "name",
              "revision",
              "_type",
              "supportedFeatures",
              "isUnknown",
              "endpointId",
              "attributes",
              "events",
              "commands",
              "subscribeAllAttributes",
              "_triggerAttributeUpdate",
              "_triggerEventUpdate",
              "isAttributeSupported",
              "isAttributeSupportedByName",
              "isCommandSupported",
              "isCommandSupportedByName",
              "getDeviceTypeListAttribute",
              "setDeviceTypeListAttribute",
              "subscribeDeviceTypeListAttribute",
              "addDeviceTypeListAttributeListener",
              "removeDeviceTypeListAttributeListener",
              "getServerListAttribute",
              "setServerListAttribute",
              "subscribeServerListAttribute",
              "addServerListAttributeListener",
              "removeServerListAttributeListener",
              "getClientListAttribute",
              "setClientListAttribute",
              "subscribeClientListAttribute",
              "addClientListAttributeListener",
              "removeClientListAttributeListener",
              "getPartsListAttribute",
              "setPartsListAttribute",
              "subscribePartsListAttribute",
              "addPartsListAttributeListener",
              "removePartsListAttributeListener",
              "getClusterRevisionAttribute",
              "setClusterRevisionAttribute",
              "subscribeClusterRevisionAttribute",
              "addClusterRevisionAttributeListener",
              "removeClusterRevisionAttributeListener",
              "getFeatureMapAttribute",
              "setFeatureMapAttribute",
              "subscribeFeatureMapAttribute",
              "addFeatureMapAttributeListener",
              "removeFeatureMapAttributeListener",
              "getAttributeListAttribute",
              "setAttributeListAttribute",
              "subscribeAttributeListAttribute",
              "addAttributeListAttributeListener",
              "removeAttributeListAttributeListener",
              "getAcceptedCommandListAttribute",
              "setAcceptedCommandListAttribute",
              "subscribeAcceptedCommandListAttribute",
              "addAcceptedCommandListAttributeListener",
              "removeAcceptedCommandListAttributeListener",
              "getGeneratedCommandListAttribute",
              "setGeneratedCommandListAttribute",
              "subscribeGeneratedCommandListAttribute",
              "addGeneratedCommandListAttributeListener",
              "removeGeneratedCommandListAttributeListener",
              "getTagListAttribute",
              "setTagListAttribute",
              "subscribeTagListAttribute",
              "addTagListAttributeListener",
              "removeTagListAttributeListener"
            ]
          }
        ],
        "child_endpoints": []
      }
    ],
    "node_information": {
      "vendor_name": "NOUS TECHNOLOGY",
      "product_name": "A8M",
      "product_id": 2268,
      "vendor_id": 5168
    }
  }

Si pas présent cela veut dire que la prise ne remonte pas l’iinfo sur Matter ?

I found the info on another forum

‘Energy consumption is only implemented in Matter version 1.3.

As long as there is no firmware update the consumption will not be reported via the Matter protocol.’

1 Like

Indeed, we must wait for NOUS to update its plug!

It’s complicated to know what’s available with Matter.

With this brand on Zigbee I could pair it directly with zigbee2mqtt.

There I had to create a Nous account, pair the plug to the Nous app and then share the plug with Matter

So does that mean a Wifi+Matter device is much more complicated to integrate than a Thread+Matter device? I thought it was plug’n’play :frowning:
It’s clear that if we have to create an account for each brand it’s going to become annoying.

Actually, it depends on the brands.

Some brands play along with Matter, but others prefer to require their own app.

With Eve, for example, you can use all their products end-to-end without an app:

We’re still in the early days of Matter; brands are testing.

As consumers, it’s also our role to complain to brands and ask for local-only (no apps) :slightly_smiling_face:

But that doesn’t have much to do with Matter, which is indeed a purely local protocol.

Eve => Thread => no account required
Nous => Wifi => account required

It’s not because a plug is Wi‑Fi that it necessarily requires creating an account; we could have the same process as the Eve Thread for a Matter Wi‑Fi plug… it’s the manufacturer’s choice

1 Like

@pierre-gilles, I’m following up about my NOUS A8M Matter WiFi plug that I paired in Gladys.

The switch is reported correctly, but I don’t have all the data related to consumption, current, voltage.

image

To test, I added the Matter integration in Home Assistant. There, all the data are reported correctly. Why not in Gladys? When you’re back from vacation, I’d be interested in understanding why.

image

1 Like

So I looked into it myself because Home Assistant also lets you download a JSON. I can give it to you if needed.
I gave this JSON to an AI and here is its conclusion: NOUS uses a manufacturer-specific cluster here:

Based on the JSON file you provided, this is a very interesting analysis. You are using Home Assistant 2025.12 and the device in question is a product of the NOUS TECHNOLOGY brand.

Here are the features I could deduce from analyzing the clusters and attributes of "Node 2":

1. Device identification
Manufacturer: NOUS TECHNOLOGY (Attribute 0/40/1)

Model: A8M (Attribute 0/40/3)

Device type: Smart plug (On/Off Plug-in Unit).

The code 266 (i.e. 0x010A) found in the Descriptor cluster of Endpoint 1 confirms that this is a power switching unit.

2. Control features (Endpoint 1)
Endpoint 1 is the one that handles the "home automation" aspect of the plug:

Switching (Cluster 0x0006 - On/Off):

The device can be turned on or off remotely.

Current state: The plug is currently Off ("1/6/0": false).

State memory: It supports configuring the state after a power outage (attributes 16384 and following).

Identify (Cluster 0x0003):

You can make the plug's LED "blink" to physically identify it among others.

Group management (Cluster 0x0004):

It can be assigned to Matter groups to be controlled simultaneously with other plugs.

3. Consumption measurement (Proprietary Cluster)
This is where it gets interesting. We see a cluster with a very high ID: 308149265 (0x125B0011).

In the current Matter ecosystem (versions 1.0 to 1.3), energy measurement was not yet fully standardized the same way for everyone. NOUS uses a manufacturer-specific cluster here to report electrical information. From the raw values in the JSON (1/308149265/...), the plug reports:

Voltage: Probably attribute 308084772 (value 2249 meaning 224.9V).

Current (amperage): Probably attribute 308084774 (value 542 meaning 54.2 mA).

Power (Watts): The other attributes correspond to active power and cumulative consumption (kWh).

4. Connectivity and Health
Protocol: It's a Matter-over-WiFi plug. We can see this because the Network Commissioning cluster (0/49) is present and configured for Wi‑Fi, unlike Thread which does not appear active here.

Signal: The plug reports an RSSI of -34 (0/54/4), which indicates an excellent Wi‑Fi connection (very close to the access point).
In the JSON of your NOUS A8M plug:

The device was designed or certified before the widespread adoption of Matter 1.3, or the manufacturer chose to use its own cluster to ensure compatibility with its legacy systems.

That's why you see IDs like 308084772 (which is a proprietary ID) instead of the standard ID 2 for voltage.

How does Home Assistant handle this?
Home Assistant has "translators" (called Discovery Schemas).

If the ID is 0x0090, Home Assistant automatically creates power sensors.

For proprietary IDs (like yours), Home Assistant's Matter integration must include a specific rule to say: "If it's a NOUS plug, then attribute X corresponds to Voltage".

Hi @_Will_71,

Thanks for your investigation, it’s very clear what’s happening :+1:

NOUS implemented energy tracking before its official integration into Matter 1.3. It is therefore a proprietary NOUS implementation, and not a standard Matter feature.

Home Assistant is able to retrieve this value because they developed a specific layer for NOUS to handle this particular case outside the Matter specification.

On our side, Gladys doesn’t handle Matter directly: we rely on the official JavaScript dependency matter-js

:backhand_index_pointing_right: GitHub - matter-js/matter.js: A complete typescript implementation of the Matter protocol specification (https://buildwithmatter.com). Includes full support for controller, device, commissioning, secure communications, device types, and cluster definitions.

I don’t know at this stage whether this library allows easy access to unofficial / non-standard attributes.

Personally, I also question the value of investing time in this kind of specificity. To me, it’s somewhat the antithesis of Matter: the goal is precisely to standardize behavior across manufacturers. If we encourage unofficial Matter implementations, this risks entrenching those practices and undermining the initiative’s credibility.

I’m actually quite surprised by Home Assistant’s position on this point: as a major player in the ecosystem, they could also set an example by strictly adhering to the specifications.

To start, could you contact NOUS to ask them if a firmware update compliant with Matter 1.3 is planned?

Thanks again for your very detailed feedback :slightly_smiling_face:

1 Like