Differentiation of shutters/blinds/doors

Hello,
with all my Somfy gear, I have exterior roller shutters, interior and exterior blinds, and now a garage door.
In the Matter integration, I only have shutters for the controls and states:




Is it possible to differentiate them?
And I’d even go so far as to add window and gate for later.
Shutter position / Shutter state
Blind position / Blind state
Door position / Door state
Window position / Window state

If needed, I can provide the identifiers from Matterbridge (for the ones I have).
Gate position / Gate state

Hi :slight_smile:

I’m not sure that’s possible — on the Matter side these 3 devices are « WindowCovering » clusters.

We should check whether on the Matterbridge side there is an attribute being communicated that indicates the type of each feature.

Can you take screenshots of Matterbridge for me?

You’re right, it only sends 0x0202-MA-windowCovering on the Matter side for all my devices :frowning:

However, we have more info on the matterbridge-somfy plugin side and it’s properly differentiated.

Example Velux roller shutter:

[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] Device: Velux Bureau 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - uniqueName RollerShutterVeluxIOComponent 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - uiClass RollerShutter 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - serial 612f437f-xxxx-xxxx-xxxx 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - deviceURL io://xxxx-xxxx-xxxx/2602070 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - commands [ 'addLockLevel', 'advancedRefresh', 'close', 'delayedStopIdentify', 'down', 'getName', 'identify', 'my', 'open', 'refreshMemorized1Position', 'removeLockLevel', 'resetLockLevels', 'setClosureAndLinearSpeed', 'setClosure', 'setDeployment', 'setMemorized1Position', 'setName', 'setPositionAndLinearSpeed', 'setPosition', 'setSecuredPosition', 'startIdentify', 'stop', 'stopIdentify', 'up', 'wink', 'pairOneWayController', 'setConfigState', 'unpairAllOneWayControllers', 'unpairOneWayController' ] 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - states [ { name: 'core:NameState', type: 3, value: 'Velux Bureau' }, { name: 'core:PriorityLockTimerState', type: 1, value: 0 }, { name: 'core:CommandLockLevelsState', type: 3, value: '[]', lastUpdateTime: 1747209967000 }, { name: 'core:StatusState', type: 3, value: 'available' }, { name: 'core:DiscreteRSSILevelState', type: 3, value: 'normal' }, { name: 'core:RSSILevelState', type: 2, value: 62 }, { name: 'core:BatteryDiscreteLevelState', type: 3, value: 'good' }, { name: 'core:ClosureState', type: 1, value: 100 }, { name: 'core:OpenClosedState', type: 3, value: 'closed' }, { name: 'core:Memorized1PositionState', type: 1, value: 0 } ] 
[23:12:22.667] [Matterbridge somfy tahoma plugin] [debug] - added with uiClass
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] Adding device: Velux Bureau 
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] - uniqueName RollerShutterVeluxIOComponent 
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] - uiClass RollerShutter 
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] - serial 612f437f-xxxx-xxxx-xxxx 
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] - deviceURL io://xxxx-xxxx-xxxx/2602070 
[23:12:22.992] [Matterbridge somfy tahoma plugin] [debug] - commands [ 'addLockLevel', 'advancedRefresh', 'close', 'delayedStopIdentify', 'down', 'getName', 'identify', 'my', 'open', 'refreshMemorized1Position', 'removeLockLevel', 'resetLockLevels', 'setClosureAndLinearSpeed', 'setClosure', 'setDeployment', 'setMemorized1Position', 'setName', 'setPositionAndLinearSpeed', 'setPosition', 'setSecuredPosition', 'startIdentify', 'stop', 'stopIdentify', 'up', 'wink', 'pairOneWayController', 'setConfigState', 'unpairAllOneWayControllers', 'unpairOneWayController' ] 
[23:12:22.993] [Matterbridge somfy tahoma plugin] [debug] - states [ { name: 'core:NameState', type: 3, value: 'Velux Bureau' }, { name: 'core:PriorityLockTimerState', type: 1, value: 0 }, { name: 'core:CommandLockLevelsState', type: 3, value: '[]', lastUpdateTime: 1747209967000 }, { name: 'core:StatusState', type: 3, value: 'available' }, { name: 'core:DiscreteRSSILevelState', type: 3, value: 'normal' }, { name: 'core:RSSILevelState', type: 2, value: 62 }, { name: 'core:BatteryDiscreteLevelState', type: 3, value: 'good' }, { name: 'core:ClosureState', type: 1, value: 100 }, { name: 'core:OpenClosedState', type: 3, value: 'closed' }, { name: 'core:Memorized1PositionState', type: 1, value: 0 } ] 
[23:12:23.007] [Matterbridge somfy tahoma plugin] [debug] - duration 30 
[23:12:23.007] [Velux Bureau] [debug] new MatterbridgeEndpoint: 0x0202-MA-windowCovering id: Velux Bureau number: undefined taglist: undefined 
[23:12:23.009] [Matterbridge] [debug] Adding bridged endpoint matterbridge-somfy-tahoma:Velux Bureau to Matterbridge aggregator node 
[23:12:23.057] [Endpoint] [info] Matterbridge.Matterbridge.VeluxBureau ready endpoint#: 37 type: MA_windowCovering (0x202) behaviors: ✓descriptor 💤matterbridge ✓identify ✓groups ✓windowCovering ✓bridgedDeviceBasicInformation ✓powerSource 
[23:12:23.108] [Matterbridge] [info] Subscribing attributes for endpoint Velux Bureau (VeluxBureau) plugin matterbridge-somfy-tahoma 
[23:12:23.116] [Matterbridge] [info] Added and registered bridged endpoint (7/7) Velux Bureau (VeluxBureau) for plugin matterbridge-somfy-tahoma

Example interior blind:

[23:12:22.671] [Matterbridge somfy tahoma plugin] [debug] Device: Velux Store 
[23:12:22.671] [Matterbridge somfy tahoma plugin] [debug] - uniqueName VerticalInteriorBlindVeluxIOComponent 
[23:12:22.672] [Matterbridge somfy tahoma plugin] [debug] - uiClass Screen 
[23:12:22.672] [Matterbridge somfy tahoma plugin] [debug] - serial 04064452-xxxx-xxxx-xxxx 
[23:12:22.672] [Matterbridge somfy tahoma plugin] [debug] - deviceURL io://xxxx-xxxx-xxxx/9733440 
[23:12:22.672] [Matterbridge somfy tahoma plugin] [debug] - commands [ 'addLockLevel', 'advancedRefresh', 'close', 'delayedStopIdentify', 'down', 'getName', 'identify', 'my', 'open', 'refreshMemorized1Position', 'removeLockLevel', 'resetLockLevels', 'setClosure', 'setMemorized1Position', 'setName', 'setPosition', 'setSecuredPosition', 'startIdentify', 'stop', 'stopIdentify', 'up', 'wink', 'pairOneWayController', 'setConfigState', 'unpairAllOneWayControllers', 'unpairOneWayController' ] 
[23:12:22.673] [Matterbridge somfy tahoma plugin] [debug] - states [ { name: 'core:NameState', type: 3, value: 'Velux Store' }, { name: 'core:PriorityLockTimerState', type: 1, value: 0 }, { name: 'core:CommandLockLevelsState', type: 3, value: '[]', lastUpdateTime: 1747209968000 }, { name: 'core:StatusState', type: 3, value: 'available' }, { name: 'core:DiscreteRSSILevelState', type: 3, value: 'normal' }, { name: 'core:RSSILevelState', type: 2, value: 80 }, { name: 'core:ClosureState', type: 1, value: 100 }, { name: 'core:OpenClosedState', type: 3, value: 'closed' } ] 
[23:12:22.673] [Matterbridge somfy tahoma plugin] [debug] - added with uiClass 
[23:12:23.184] [Matterbridge somfy tahoma plugin] [debug] Adding device: Velux Store 
[23:12:23.184] [Matterbridge somfy tahoma plugin] [debug] - uniqueName VerticalInteriorBlindVeluxIOComponent 
[23:12:23.184] [Matterbridge somfy tahoma plugin] [debug] - uiClass Screen 
[23:12:23.184] [Matterbridge somfy tahoma plugin] [debug] - serial 04064452-xxxx-xxxx-xxxx 
[23:12:23.184] [Matterbridge somfy tahoma plugin] [debug] - deviceURL io://xxxx-xxxx-xxxx/9733440 
[23:12:23.185] [Matterbridge somfy tahoma plugin] [debug] - commands [ 'addLockLevel', 'advancedRefresh', 'close', 'delayedStopIdentify', 'down', 'getName', 'identify', 'my', 'open', 'refreshMemorized1Position', 'removeLockLevel', 'resetLockLevels', 'setClosure', 'setMemorized1Position', 'setName', 'setPosition', 'setSecuredPosition', 'startIdentify', 'stop', 'stopIdentify', 'up', 'wink', 'pairOneWayController', 'setConfigState', 'unpairAllOneWayControllers', 'unpairOneWayController' ] 
[23:12:23.185] [Matterbridge somfy tahoma plugin] [debug] - states [ { name: 'core:NameState', type: 3, value: 'Velux Store' }, { name: 'core:PriorityLockTimerState', type: 1, value: 0 }, { name: 'core:CommandLockLevelsState', type: 3, value: '[]', lastUpdateTime: 1747209968000 }, { name: 'core:StatusState', type: 3, value: 'available' }, { name: 'core:DiscreteRSSILevelState', type: 3, value: 'normal' }, { name: 'core:RSSILevelState', type: 2, value: 80 }, { name: 'core:ClosureState', type: 1, value: 100 }, { name: 'core:OpenClosedState', type: 3, value: 'closed' } ] 
[23:12:23.185] [Matterbridge somfy tahoma plugin] [debug] - duration 30 
[23:12:23.185] [Velux Store] [debug] new MatterbridgeEndpoint: 0x0202-MA-windowCovering id: Velux Store number: undefined taglist: undefined 
[23:12:23.189] [Matterbridge] [debug] Adding bridged endpoint matterbridge-somfy-tahoma:Velux Store to Matterbridge aggregator node 
[23:12:23.199] [Endpoint] [info] Matterbridge.Matterbridge.VeluxStore ready endpoint#: 40 type: MA_windowCovering (0x202) behaviors: ✓descriptor 💤matterbridge ✓identify ✓groups ✓windowCovering ✓bridgedDeviceBasicInformation ✓powerSource 
[23:12:23.221] [Matterbridge] [info] Subscribing attributes for endpoint Velux Store (VeluxStore) plugin matterbridge-somfy-tahoma 
[23:12:23.221] [Matterbridge] [info] Added and registered bridged endpoint (10/10) Velux Store (VeluxStore) for plugin matterbridge-somfy-tahoma

I’ll see if I can find any info on Matter regarding the differentiation.

Can you take screenshots of the Matterbridge interface for me?

I just found in the Matter logs of Matterbridge a « line » that seems exposed to show the device type that also appears in the Matterbrige UI:
MA_windowCovering(0x33)/BridgedDeviceBasicInformation(0x39)/productName(0x3)="GarageDoor" (for example)






I’m not sure that’s part of the Matter standard; it’s just an open field (productName) that’s populated by Matterbridge.

For me to be able to differentiate, there needs to be an official way to identify the device type.

Can you take a full screenshot for me? ^^

Do you need all the Clusters for device lines from one of the devices?
The thing is I tested the different lines and only uniqueId, productName, nodeLabel and serialNumber differ, all the others are absolutely identical :confused:







In that case you need to talk to the developer of the Somfy Matterbridge integration! :slight_smile:

Often, it’s the « featureMap » attribute that contains booleans to identify what it is.

Some thermostat devices, for example, differentiate heaters from air conditioners by using an attribute « heating: true » vs « cooling: true »

1 Like

Hi @pierre-gilles
Are you familiar with the EndProductTypeEnum in your Matter integration?

It’s what potentially allows differentiating device types.

That doesn’t ring a bell!

Is that an attribute you find when you download Matter nodes as JSON?

Search using different types of case.

J’ai pris un exemple et je vois bien le EndProductType :

              {
                "id": "258",
                "name": "WindowCovering",
                "attributes": [
                  "0",
                  "1",
                  "2",
                  "3",
                  "4",
                  "5",
                  "6",
                  "7",
                  "8",
                  "9",
                  "10",
                  "11",
                  "12",
                  "13",
                  "14",
                  "15",
                  "16",
                  "17",
                  "18",
                  "19",
                  "23",
                  "26",
                  "65528",
                  "65529",
                  "65531",
                  "65532",
                  "65533",
-->>              "type",
                  "configStatus",
                  "operationalStatus",
-->>              "endProductType",
                  "mode",
                  "safetyStatus",
                  "physicalClosedLimitLift",
                  "physicalClosedLimitTilt",
                  "currentPositionLift",
                  "currentPositionTilt",
                  "numberOfActuationsLift",
                  "numberOfActuationsTilt",
                  "currentPositionLiftPercentage",
                  "currentPositionTiltPercentage",
                  "targetPositionLiftPercent100ths",
                  "targetPositionTiltPercent100ths",
                  "currentPositionLiftPercent100ths",
                  "currentPositionTiltPercent100ths",
                  "installedOpenLimitLift",
                  "installedClosedLimitLift",
                  "installedOpenLimitTilt",
                  "installedClosedLimitTilt",
                  "clusterRevision",
                  "featureMap",
                  "attributeList",
                  "acceptedCommandList",
                  "generatedCommandList"
                ],
                "commands": [
                  "0",
                  "1",
                  "2",
                  "4",
                  "5",
                  "7",
                  "8",
                  "upOrOpen",
                  "downOrClose",
                  "stopMotion",
                  "goToLiftValue",
                  "goToLiftPercentage",
                  "goToTiltValue",
                  "goToTiltPercentage"
                ],
                "all_keys": [
                  "id",
                  "name",
                  "revision",
                  "_type",
                  "supportedFeatures",
                  "isUnknown",
                  "endpointId",
                  "attributes",
                  "events",
                  "commands",
                  "subscribeAllAttributes",
                  "_triggerAttributeUpdate",
                  "_triggerEventUpdate",
                  "isAttributeSupported",
                  "isAttributeSupportedByName",
                  "isCommandSupported",
                  "isCommandSupportedByName",
                  "getTypeAttribute",
                  "setTypeAttribute",
                  "subscribeTypeAttribute",
                  "addTypeAttributeListener",
                  "removeTypeAttributeListener",
                  "getConfigStatusAttribute",
                  "setConfigStatusAttribute",
                  "subscribeConfigStatusAttribute",
                  "addConfigStatusAttributeListener",
                  "removeConfigStatusAttributeListener",
                  "getOperationalStatusAttribute",
                  "setOperationalStatusAttribute",
                  "subscribeOperationalStatusAttribute",
                  "addOperationalStatusAttributeListener",
                  "removeOperationalStatusAttributeListener",
                  "getEndProductTypeAttribute",
                  "setEndProductTypeAttribute",
                  "subscribeEndProductTypeAttribute",
                  "addEndProductTypeAttributeListener",
                  "removeEndProductTypeAttributeListener",
                  "getModeAttribute",
                  "setModeAttribute",
                  "subscribeModeAttribute",
                  "addModeAttributeListener",
                  "removeModeAttributeListener",
                  "getSafetyStatusAttribute",
                  "setSafetyStatusAttribute",
                  "subscribeSafetyStatusAttribute",
                  "addSafetyStatusAttributeListener",
                  "removeSafetyStatusAttributeListener",
                  "getPhysicalClosedLimitLiftAttribute",
                  "setPhysicalClosedLimitLiftAttribute",
                  "subscribePhysicalClosedLimitLiftAttribute",
                  "addPhysicalClosedLimitLiftAttributeListener",
                  "removePhysicalClosedLimitLiftAttributeListener",
                  "getPhysicalClosedLimitTiltAttribute",
                  "setPhysicalClosedLimitTiltAttribute",
                  "subscribePhysicalClosedLimitTiltAttribute",
                  "addPhysicalClosedLimitTiltAttributeListener",
                  "removePhysicalClosedLimitTiltAttributeListener",
                  "getCurrentPositionLiftAttribute",
                  "setCurrentPositionLiftAttribute",
                  "subscribeCurrentPositionLiftAttribute",
                  "addCurrentPositionLiftAttributeListener",
                  "removeCurrentPositionLiftAttributeListener",
                  "getCurrentPositionTiltAttribute",
                  "setCurrentPositionTiltAttribute",
                  "subscribeCurrentPositionTiltAttribute",
                  "addCurrentPositionTiltAttributeListener",
                  "removeCurrentPositionTiltAttributeListener",
                  "getNumberOfActuationsLiftAttribute",
                  "setNumberOfActuationsLiftAttribute",
                  "subscribeNumberOfActuationsLiftAttribute",
                  "addNumberOfActuationsLiftAttributeListener",
                  "removeNumberOfActuationsLiftAttributeListener",
                  "getNumberOfActuationsTiltAttribute",
                  "setNumberOfActuationsTiltAttribute",
                  "subscribeNumberOfActuationsTiltAttribute",
                  "addNumberOfActuationsTiltAttributeListener",
                  "removeNumberOfActuationsTiltAttributeListener",
                  "getCurrentPositionLiftPercentageAttribute",
                  "setCurrentPositionLiftPercentageAttribute",
                  "subscribeCurrentPositionLiftPercentageAttribute",
                  "addCurrentPositionLiftPercentageAttributeListener",
                  "removeCurrentPositionLiftPercentageAttributeListener",
                  "getCurrentPositionTiltPercentageAttribute",
                  "setCurrentPositionTiltPercentageAttribute",
                  "subscribeCurrentPositionTiltPercentageAttribute",
                  "addCurrentPositionTiltPercentageAttributeListener",
                  "removeCurrentPositionTiltPercentageAttributeListener",
                  "getTargetPositionLiftPercent100thsAttribute",
                  "setTargetPositionLiftPercent100thsAttribute",
                  "subscribeTargetPositionLiftPercent100thsAttribute",
                  "addTargetPositionLiftPercent100thsAttributeListener",
                  "removeTargetPositionLiftPercent100thsAttributeListener",
                  "getTargetPositionTiltPercent100thsAttribute",
                  "setTargetPositionTiltPercent100thsAttribute",
                  "subscribeTargetPositionTiltPercent100thsAttribute",
                  "addTargetPositionTiltPercent100thsAttributeListener",
                  "removeTargetPositionTiltPercent100thsAttributeListener",
                  "getCurrentPositionLiftPercent100thsAttribute",
                  "setCurrentPositionLiftPercent100thsAttribute",
                  "subscribeCurrentPositionLiftPercent100thsAttribute",
                  "addCurrentPositionLiftPercent100thsAttributeListener",
                  "removeCurrentPositionLiftPercent100thsAttributeListener",
                  "getCurrentPositionTiltPercent100thsAttribute",
                  "setCurrentPositionTiltPercent100thsAttribute",
                  "subscribeCurrentPositionTiltPercent100thsAttribute",
                  "addCurrentPositionTiltPercent100thsAttributeListener",
                  "removeCurrentPositionTiltPercent100thsAttributeListener",
                  "getInstalledOpenLimitLiftAttribute",
                  "setInstalledOpenLimitLiftAttribute",
                  "subscribeInstalledOpenLimitLiftAttribute",
                  "addInstalledOpenLimitLiftAttributeListener",
                  "removeInstalledOpenLimitLiftAttributeListener",
                  "getInstalledClosedLimitLiftAttribute",
                  "setInstalledClosedLimitLiftAttribute",
                  "subscribeInstalledClosedLimitLiftAttribute",
                  "addInstalledClosedLimitLiftAttributeListener",
                  "removeInstalledClosedLimitLiftAttributeListener",
                  "getInstalledOpenLimitTiltAttribute",
                  "setInstalledOpenLimitTiltAttribute",
                  "subscribeInstalledOpenLimitTiltAttribute",
                  "addInstalledOpenLimitTiltAttributeListener",
                  "removeInstalledOpenLimitTiltAttributeListener",
                  "getInstalledClosedLimitTiltAttribute",
                  "setInstalledClosedLimitTiltAttribute",
                  "subscribeInstalledClosedLimitTiltAttribute",
                  "addInstalledClosedLimitTiltAttributeListener",
                  "removeInstalledClosedLimitTiltAttributeListener",
                  "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",
                  "upOrOpen",
                  "downOrClose",
                  "stopMotion",
                  "goToLiftValue",
                  "goToLiftPercentage",
                  "goToTiltValue",
                  "goToTiltPercentage"
                ]
              }

En essayant de regarder un peu le code de Matterbridge, j’ai l’impression que ces 2 paramètres (Type et EndProductType) restent sur la même valeur par défaut, ce qui correspond à du Roller Shade dans la spec Matter 1.4.1 :


2 Likes

Excellent :heart_eyes:

Can you create a feature request « Matter: Differentiate shutters/blinds/doors with endProductType »? :slight_smile:

2 Likes

and here it is : [Matter] Différencier les volets/stores/portes avec le endProductType

1 Like