diff --git a/src/content/docs/components/sensor/dlms_meter.mdx b/src/content/docs/components/sensor/dlms_meter.mdx
index 3cf5ec1f1f..5d4765ab89 100644
--- a/src/content/docs/components/sensor/dlms_meter.mdx
+++ b/src/content/docs/components/sensor/dlms_meter.mdx
@@ -1,161 +1,363 @@
---
title: "DLMS Meter"
-description: "Instructions for setting up DLMS (COSEM) smart meter integration using an M-Bus to UART adapter."
+description: "Instructions for setting up DLMS (COSEM) smart meter integration"
---
import APIClass from '@components/APIClass.astro';
import APIRef from '@components/APIRef.astro';
-import { Image } from 'astro:assets';
-The `dlms_meter` component connects to smart meters which use the encrypted **DLMS/COSEM** protocol over UART. These
-smart meters are (for example) widely deployed in Austria.
+The `dlms_meter` component connects to smart meters which use the **DLMS/COSEM** protocol in PUSH mode over UART.
+These smart meters are widely deployed globally.
-**An M-Bus to UART adapter is required.** You must also request the 32‑character hexadecimal decryption key from your
-energy provider / grid operator.
+The component does not transmit data to the meter. The meter periodically broadcasts frames. ESPHome listens, decodes
+(and decrypts if necessary), and updates the configured sensors as data arrives.
-This component is passive; it does not transmit data to the meter. The meter periodically broadcasts frames (often
-about every 5 seconds). ESPHome listens, decrypts and updates the configured sensors as data arrives.
+> [!NOTE]
+> An adapter (like an `M-Bus to UART module`) is required to connect the EspHome board to the smart meter.
+>
+> For **encrypted meters**, you must request a 32-character hexadecimal **decryption key** from your energy provider.
-
+
-## Example (Generic Provider)
+## Configuration
-```yaml
-# Example configuration entry for a generic grid operator
-uart:
- rx_pin: GPIOXX # Adjust for where the M-Bus adapter RX is connected
- baud_rate: 2400
- rx_buffer_size: 1024 # Needed for large frames
+This component requires a [UART bus](/components/uart/) to be configured.
+
+> [!TIP]
+> The UART configuration depends on your specific meter hardware.
+> Be sure to consult your provider or meter's specifications.
+```yaml
dlms_meter:
- decryption_key: "01234567890123456789012345678901" # Replace with your key
+ id: dlms_meter_hub
+ uart_id: uart_dlms_bus
sensor:
- platform: dlms_meter
- voltage_l1:
- name: "Voltage L1"
- voltage_l2:
- name: "Voltage L2"
- voltage_l3:
- name: "Voltage L3"
- current_l1:
- name: "Current L1"
- current_l2:
- name: "Current L2"
- current_l3:
- name: "Current L3"
- active_power_plus:
- name: "Active power taken from grid"
- active_power_minus:
- name: "Active power put into grid"
- active_energy_plus:
- name: "Active energy taken from grid"
- active_energy_minus:
- name: "Active energy put into grid"
- reactive_energy_plus:
- name: "Reactive energy taken from grid"
- reactive_energy_minus:
- name: "Reactive energy put into grid"
+ dlms_meter_id: dlms_meter_hub
+ obis_code: "1.0.1.7.0.255"
+ name: "Active power taken from grid"
+```
-text_sensor:
+## Configuration variables
+
+- **id** (*Optional*, [ID](/guides/configuration-types#config-id)): The ID of the `dlms_meter` component.
+- **uart_id** (*Optional*, [ID](/guides/configuration-types#config-id)): The ID of the UART component that is
+connected to the smart meter.
+- **decryption_key** (*Optional*, string): Specify if your smart meter uses encryption. You should request this key
+from your electricity provider (32 hex characters, case-insensitive).
+- **auth_key** (*Optional*, string): Authentication key. Specify if your smart meter uses encryption with
+authentication. You should request this key from your electricity provider. Used for `General-GLO-Ciphering` and
+`General-DED-Ciphering` APDUs.
+- **skip_crc** (*Optional*, boolean): Skip CRC check. Some smart meters use the wrong polynomial to calculate CRC.
+In such cases, you can use this flag as a workaround. Defaults to `false`.
+- **custom_patterns** (*Optional*, list): While the `dlms_meter` natively supports most devices, some meters use
+unique payload structures. If your meter's data isn't being read correctly, use this field to define a **custom AXDR
+descriptor pattern** that tells the system how to parse the incoming data.
+
+## Platforms
+
+### Sensor, text sensor, and binary sensor
+
+All platforms (`sensor`, `text_sensor`, `binary_sensor`) support dynamic mapping using the `obis_code` property.
+This allows you to decode nearly any property your meter emits.
+
+- **dlms_meter_id** (*Optional*, [ID](/guides/configuration-types#config-id)): Manually specify the ID of the
+`dlms_meter` hub if you have multiple.
+- **obis_code** (**Required**, string): The OBIS code of the value you want to read. The code supports flexible formats
+like `1-0:32.7.0` or `1.0.32.7.0.255`.
+
+When defining your sensors, it is recommended to include standard ESPHome sensor properties such as
+`unit_of_measurement`, `accuracy_decimals`, `device_class`, and `state_class`.
+The exact configuration will vary depending on the specific value you are reading (e.g., energy vs. power vs. voltage).
+
+Here is an example of how to configure an energy sensor so it displays correctly with Home Assistant's Energy Dashboard:
+
+```yaml
+sensor:
- platform: dlms_meter
- timestamp:
- name: "Timestamp"
+ dlms_meter_id: dlms_meter_hub
+ obis_code: "1.0.1.8.0.255"
+ name: "Energy Consumed"
+ unit_of_measurement: "kWh"
+ accuracy_decimals: 3
+ device_class: energy
+ state_class: total_increasing
```
-### Example (Netz Noe / EVN)
+### Finding your meter's OBIS codes
+
+Before using this method, it is highly recommended to check your meter's manual or your energy provider's documentation
+for a list of supported OBIS codes.
+
+If you are configuring your meter for the first time and do not know which OBIS codes it broadcasts, you can temporarily
+increase the logging level to `VERBOSE`. The component will print all successfully parsed OBIS codes and their values to
+the ESPHome log.
```yaml
-uart:
- rx_pin: GPIOXX
- baud_rate: 2400
- rx_buffer_size: 1024
+logger:
+ level: VERBOSE
+ initial_level: DEBUG
+ logs:
+ dlms_meter: VERBOSE
+```
-dlms_meter:
- decryption_key: "01234567890123456789012345678901" # Replace with your key
- provider: netznoe
+In this configuration, the global `level` is set to `VERBOSE` because ESPHome will otherwise exclude lower-severity log
+messages at compile time (any log message with a lower severity will not be shown).
+
+To prevent your console from being flooded with verbose messages from every component,
+`initial_level` restores the standard default of `DEBUG` dynamically at run time,
+while the `logs` mapping manually sets the specific `dlms_meter` tag to remain at `VERBOSE`.
+
+> [!WARNING]
+> Increasing the log level severity can impact the performance of your ESP application and increase memory size.
+> Always **revert to default log levels** for daily use.
+
+> [!TIP]
+> If you are building custom patterns or need to capture the raw hex payload for troubleshooting, change the `dlms_meter`
+> log level to `VERY_VERBOSE`. This will output the full raw buffer and the decrypted AXDR payload.
+For more details, refer to the [Logger Component](/components/logger/).
+
+### Legacy keys
+
+For backwards compatibility, the legacy predefined keys from earlier versions are still fully supported and mapped
+automatically to their respective OBIS codes. Add only the ones you need. All support standard options from their
+respective platform domains.
+
+```yaml
sensor:
- platform: dlms_meter
+ dlms_meter_id: dlms_meter_hub
voltage_l1:
- name: "Voltage L1"
+ name: "Voltage Phase 1"
voltage_l2:
- name: "Voltage L2"
- voltage_l3:
- name: "Voltage L3"
- current_l1:
- name: "Current L1"
- current_l2:
- name: "Current L2"
- current_l3:
- name: "Current L3"
- active_power_plus:
- name: "Active power taken from grid"
- active_power_minus:
- name: "Active power put into grid"
- active_energy_plus:
- name: "Active energy taken from grid"
- active_energy_minus:
- name: "Active energy put into grid"
- power_factor: # EVN specific
- name: "Power Factor"
+ name: "Voltage Phase 2"
text_sensor:
- platform: dlms_meter
- timestamp:
- name: "Timestamp"
- meternumber: # EVN specific
+ dlms_meter_id: dlms_meter_hub
+ meternumber:
name: "Meter Number"
```
-## Component Configuration
+**Sensors:**
-### Configuration Variables
+- **voltage_l1** (`1.0.32.7.0.255`): Voltage Phase 1.
+- **voltage_l2** (`1.0.52.7.0.255`): Voltage Phase 2.
+- **voltage_l3** (`1.0.72.7.0.255`): Voltage Phase 3.
+- **current_l1** (`1.0.31.7.0.255`): Current Phase 1.
+- **current_l2** (`1.0.51.7.0.255`): Current Phase 2.
+- **current_l3** (`1.0.71.7.0.255`): Current Phase 3.
+- **active_power_plus** (`1.0.1.7.0.255`): Active power taken from grid.
+- **active_power_minus** (`1.0.2.7.0.255`): Active power put into grid.
+- **active_energy_plus** (`1.0.1.8.0.255`): Cumulative active energy taken from grid.
+- **active_energy_minus** (`1.0.2.8.0.255`): Cumulative active energy exported to grid.
+- **reactive_energy_plus** (`1.0.3.8.0.255`): Reactive energy taken from grid.
+- **reactive_energy_minus** (`1.0.4.8.0.255`): Reactive energy exported to grid.
+- **power_factor** (`1.0.13.7.0.255`): Power factor.
-- **decryption_key** (**Required**, string, 32 hex chars, case-insensitive, templatable): Key used to decrypt DLMS telegrams.
- Obtain this from your provider / grid operator.
-- **provider** (*Optional*): Grid operator profile. Options:
- - `generic` (default) – works for most operators.
- - `netznoe` – Netz Noe / EVN specific mapping.
+**Text Sensors:**
-## Sensor
+- **timestamp** (`0.0.1.0.0.255`): Timestamp included in the received frame.
+- **meternumber** (`0.0.96.1.0.255`): Meter number reported by the device.
-Not all sensors are available on all meters. Provider specific sensors are listed separately.
+## Advanced configuration
-### Configuration Variables
+### Advanced configuration example
-Each of the following entries is *optional*; add only the ones you need. All support the standard [Sensor](/components/sensor) options.
+This example demonstrates how to use the optional configuration variables for encrypted meters or those requiring custom
+parsing patterns.
-- **voltage_l1**: Voltage Phase 1.
-- **voltage_l2**: Voltage Phase 2.
-- **voltage_l3**: Voltage Phase 3.
-- **current_l1**: Current Phase 1.
-- **current_l2**: Current Phase 2.
-- **current_l3**: Current Phase 3.
-- **active_power_plus**: Active power taken from grid.
-- **active_power_minus**: Active power put into grid.
-- **active_energy_plus**: Cumulative active energy taken from grid.
-- **active_energy_minus**: Cumulative active energy exported to grid.
-- **reactive_energy_plus**: Reactive energy taken from grid.
-- **reactive_energy_minus**: Reactive energy exported to grid.
+```yaml
+dlms_meter:
+ id: dlms_meter_hub
+ uart_id: uart_dlms_bus
+ decryption_key: "00112233445566778899AABBCCDDEEFF"
+ auth_key: "00112233445566778899AABBCCDDEEFF"
+ skip_crc: false
+ custom_patterns:
+ - pattern: "TO, TV"
+ name: "flat OBIS + value pairs"
+ priority: 15
+ default_obis: "1.0.96.1.0.255"
+```
+
+### Custom patterns
+
+You can define a custom pattern simply by passing its pattern string, or by defining an object with additional
+properties:
-#### Netz Noe / EVN Additional Sensor
+- **pattern** (**Required**, string): The DSL-based pattern string (e.g., `"TO, TV"`).
+- **name** (*Optional*, string): A name for the pattern.
+- **priority** (*Optional*, int): The priority of the pattern (lower number is tried first). Defaults to `0`.
+- **default_obis** (*Optional*, string): The fallback OBIS code to use if the pattern captures no OBIS code. Requires
+**name** to be set. Formatted like `1-0:96.1.0` or `1.0.96.1.0.255`.
-- **power_factor**: Power factor. All options from [Sensor](/components/sensor).
+#### Built-in patterns
-## Text Sensor
+The `dlms_meter` component loads several built-in patterns by default. Your custom patterns will be evaluated alongside
+these based on their configured `priority`.
-### Configuration Variables
+| Name | Priority | Typical use |
+|-------|---------:|-------------------------------------------|
+| `T1` | 10 | class ID, tagged OBIS, scaler, value |
+| `T2` | 20 | tagged OBIS, value, scaler-unit structure |
+| `T3` | 30 | value first, class ID, scaler-unit, OBIS |
+| `ADV` | 40 | untagged ZPA/Aidon-style layouts |
-All text sensor entries are *optional* and support standard [Text Sensor](/components/text_sensor#config-text_sensor) options.
+#### Common custom pattern examples
-- **timestamp**: Timestamp included in the received frame.
+Here are some common structures you might encounter on less standard meters:
+
+```yaml
+dlms_meter:
+ # ...
+ custom_patterns:
+ - pattern: "TC, TO, TDTM"
+ name: "datetime value"
+ - pattern: "C, O, A, V, TS, TU"
+ name: "untagged flat"
+ - pattern: "TO, TV, S(TS, TU)"
+ name: "tagged with scaler-unit"
+ - pattern: "TO, TV"
+ name: "flat OBIS + value pairs (no scaler)"
+ - pattern: "L, TSTR"
+ name: "last element as string"
+ - pattern: "TOW, TV, TSU"
+ name: "Landis+Gyr swapped OBIS"
+```
-#### Netz Noe / EVN Additional Text Sensor
+### Token reference for patterns
+
+| Token | Meaning | Hex example |
+|----------------|--------------------------------------------|---------------------------------|
+| `F` | first element guard | position check only |
+| `L` | last element guard | position check only |
+| `C` | class ID, 2-byte uint16 without tag | `00 03` |
+| `TC` | tagged class ID | `12 00 03` |
+| `O` | OBIS code, 6-byte octet string without tag | `01 00 01 08 00 FF` |
+| `TO` | tagged OBIS code | `09 06 01 00 01 08 00 FF` |
+| `TOW` | tagged OBIS with swapped tag bytes | `06 09 01 00 1F 07 00 FF` |
+| `A` | attribute index, 1-byte uint8 without tag | `02` |
+| `TA` | tagged attribute | `11 02` or `0F 02` |
+| `V` / `TV` | generic value | `06 00 00 07 A4` |
+| `TSTR` | tagged string-like value | `09 08 38 34 38 39 35 31 32 36` |
+| `TDTM` | tagged 12-byte date-time value | `19 ...` or `09 0C ...` |
+| `TS` | tagged scaler | `0F FF` |
+| `TU` | tagged unit enum | `16 23` |
+| `TSU` | tagged scaler-unit pair | `02 02 0F FF 16 23` |
+| `S(x, y, ...)` | inline sub-structure | `02 03` |
+| `DN` | descend into nested structure | control token |
+| `UP` | return from nested structure | control token |
+
+---
+
+## Supported Meters
+
+> [!IMPORTANT]
+> Always check if your meter reading already works natively with the default settings
+> before adding any `custom_patterns`. The component's built-in parser handles many standard meters automatically.
+
+### Natively Supported (No Custom Configuration Required)
+**The vast majority of standard-compliant smart meters are supported right out of the box.**
+If your meter follows the official DLMS specifications,
+you generally only need to provide the UART pins and your desired OBIS codes.
+
+We have explicitly tested and confirmed native support for standard meters including (but not limited to):
+
+**Sagemcom XT211**, **Energomera**, and **Kaifa MA304H3E**.
+
+### Specific meter configurations
+Some manufacturers implement the DLMS standard using non-standard object structuring or framing.
+Below are the tested configuration parameters required for these specific meters:
+
+**Salzburg Netz**
+```yaml
+dlms_meter:
+ # ...
+ custom_patterns:
+ - pattern: "TO, TDTM"
+ - pattern: "S(TO, TV)"
+```
+
+**Iskra 550**
+```yaml
+dlms_meter:
+ # ...
+ custom_patterns:
+ - pattern: "S(TO, TV)"
+```
+
+**Norway HAN (Aidon 1-phase and 3-phase)**
+```yaml
+dlms_meter:
+ # ...
+ custom_patterns:
+ - pattern: "F, S(TO, TDTM)"
+ name: "DateTime"
+ - pattern: "S(TO, TV, TSU)"
+ name: "Obis-Value-Scaler-Unit"
+ - pattern: "S(TO, TV)"
+```
+
+**Landis+Gyr ZMF100**
+*: This specific meter sends invalid Frame Check Sequences (FCS) and requires skipping the CRC check.*
+```yaml
+dlms_meter:
+ # ...
+ skip_crc: true
+ custom_patterns:
+ - pattern: "S(TO, TDTM)"
+ - pattern: "S(TO, TV)"
+ - pattern: "TOW, TV, TSU"
+```
+
+**Landis+Gyr E450**
+*: This meter uses encryption and requires a decryption key from your provider.*
+```yaml
+dlms_meter:
+ # ...
+ decryption_key: "YOUR_32_CHAR_HEX_KEY"
+ custom_patterns:
+ - pattern: "F, TDTM"
+ name: "DateTime"
+ - pattern: "TO, TV"
+ name: "Obis-Value Pair"
+```
+
+**Kamstrup Omnipower**
+*: This meter uses encryption. Some regional variants also mandate an Authentication Key.*
+```yaml
+dlms_meter:
+ # ...
+ decryption_key: "YOUR_32_CHAR_HEX_KEY"
+ auth_key: "YOUR_32_CHAR_AUTH_KEY" # Add if required by your provider
+ custom_patterns:
+ - pattern: "F, TSTR"
+ name: "Obis List Ver"
+ - pattern: "TO, TV"
+ name: "Code-Value Pair"
+```
+
+**Netz NOE P1 (M-Bus)**
+*: Requires encryption. The MeterID is untagged and requires a fallback default OBIS mapping.*
+```yaml
+dlms_meter:
+ # ...
+ decryption_key: "YOUR_32_CHAR_HEX_KEY"
+ custom_patterns:
+ - pattern: "L, TSTR"
+ name: "MeterID"
+ default_obis: "0.0.96.1.0.255"
+ - pattern: "S(TO, TV, TSU)"
+ name: "Obis-Value-Scaler-Unit"
+```
-- **meternumber**: Meter number reported by the device.
+*(Additional instructions and specific `custom_patterns` for meters from manufacturers can be added here
+as users report the specific setups required for their unique smart meter firmware.)*
-## See Also
+## See also
-
-