|  | 
| 36 | 36 | 
 | 
| 37 | 37 | LOGGER = logging.getLogger(__name__) | 
| 38 | 38 | 
 | 
|  | 39 | +# Due to variances in labeling implementations, labels are vendor and product specific. | 
|  | 40 | +# This dictionary defines which labels to use for specific vendor/product combinations. | 
|  | 41 | +# The keys are vendor IDs, the values are dictionaries with product IDs as keys | 
|  | 42 | +# and lists of label names to use as values. If the value is None, no labels are used | 
|  | 43 | +VENDOR_LABELING_LIST: dict[int, dict[int, list[str] | None]] = { | 
|  | 44 | +    4488: {259: ["position"]},  # TP-Link Dual Outdoor Plug US | 
|  | 45 | +    4874: {105: ["orientation"]},  # Eve Energy dual Outlet US | 
|  | 46 | +    4961: { | 
|  | 47 | +        1: ["inovelliname", "label", "name", "button"],  # Inovelli VTM31 | 
|  | 48 | +        2: ["label", "devicetype", "button"],  # Inovelli VTM35 | 
|  | 49 | +        4: None,  # Inovelli VTM36 | 
|  | 50 | +        16: ["label", "name", "button"],  # Inovelli VTM30 | 
|  | 51 | +    }, | 
|  | 52 | +} | 
|  | 53 | + | 
| 39 | 54 | 
 | 
| 40 | 55 | def catch_matter_error[_R, **P]( | 
| 41 | 56 |     func: Callable[Concatenate[MatterEntity, P], Coroutine[Any, Any, _R]], | 
| @@ -112,30 +127,47 @@ def __init__( | 
| 112 | 127 |             if self._platform_translation_key and not self.translation_key: | 
| 113 | 128 |                 self._attr_translation_key = self._platform_translation_key | 
| 114 | 129 | 
 | 
| 115 |  | -        # prefer the label attribute for the entity name | 
| 116 |  | -        # Matter has a way for users and/or vendors to specify a name for an endpoint | 
| 117 |  | -        # which is always preferred over a standard HA (generated) name | 
| 118 |  | -        for attr in ( | 
| 119 |  | -            clusters.FixedLabel.Attributes.LabelList, | 
| 120 |  | -            clusters.UserLabel.Attributes.LabelList, | 
| 121 |  | -        ): | 
| 122 |  | -            if not (labels := self.get_matter_attribute_value(attr)): | 
| 123 |  | -                continue | 
| 124 |  | -            for label in labels: | 
| 125 |  | -                if label.label not in ["Label", "Button"]: | 
| 126 |  | -                    continue | 
| 127 |  | -                # fixed or user label found: use it | 
| 128 |  | -                label_value: str = label.value | 
| 129 |  | -                # in the case the label is only the label id, use it as postfix only | 
| 130 |  | -                if label_value.isnumeric(): | 
| 131 |  | -                    self._name_postfix = label_value | 
| 132 |  | -                else: | 
| 133 |  | -                    self._attr_name = label_value | 
| 134 |  | -                break | 
|  | 130 | +        # Matter labels can be used to modify the entity name | 
|  | 131 | +        # by appending the text. | 
|  | 132 | +        if name_modifier := self._get_name_modifier(): | 
|  | 133 | +            self._name_postfix = name_modifier | 
| 135 | 134 | 
 | 
| 136 | 135 |         # make sure to update the attributes once | 
| 137 | 136 |         self._update_from_device() | 
| 138 | 137 | 
 | 
|  | 138 | +    def _find_matching_labels(self) -> list[str]: | 
|  | 139 | +        """Find all labels for a Matter entity.""" | 
|  | 140 | + | 
|  | 141 | +        device_info = self._endpoint.device_info | 
|  | 142 | +        labeling_list = VENDOR_LABELING_LIST.get(device_info.vendorID, {}).get( | 
|  | 143 | +            device_info.productID | 
|  | 144 | +        ) | 
|  | 145 | + | 
|  | 146 | +        # get the labels from the UserLabel and FixedLabel clusters | 
|  | 147 | +        user_label_list: list[clusters.UserLabel.Structs.LabelStruct] = ( | 
|  | 148 | +            self.get_matter_attribute_value(clusters.UserLabel.Attributes.LabelList) | 
|  | 149 | +            or [] | 
|  | 150 | +        ) | 
|  | 151 | +        fixed_label_list: list[clusters.FixedLabel.Structs.LabelStruct] = ( | 
|  | 152 | +            self.get_matter_attribute_value(clusters.FixedLabel.Attributes.LabelList) | 
|  | 153 | +            or [] | 
|  | 154 | +        ) | 
|  | 155 | + | 
|  | 156 | +        found_labels: list[str] = [ | 
|  | 157 | +            lbl.value | 
|  | 158 | +            for label in labeling_list or [] | 
|  | 159 | +            for lbl in (*user_label_list, *fixed_label_list) | 
|  | 160 | +            if lbl.label.lower() == label | 
|  | 161 | +        ] | 
|  | 162 | +        return found_labels | 
|  | 163 | + | 
|  | 164 | +    def _get_name_modifier(self) -> str | None: | 
|  | 165 | +        """Get the name modifier for the entity.""" | 
|  | 166 | + | 
|  | 167 | +        if found_labels := self._find_matching_labels(): | 
|  | 168 | +            return found_labels[0] | 
|  | 169 | +        return None | 
|  | 170 | + | 
| 139 | 171 |     async def async_added_to_hass(self) -> None: | 
| 140 | 172 |         """Handle being added to Home Assistant.""" | 
| 141 | 173 |         await super().async_added_to_hass() | 
|  | 
0 commit comments