Simple DSMR parser with custom fields (for non-Dutch users...)

Hi everybody,

I have a smart reader with a P1 port and I connected it to an ESP32-S3-WROOM-1 platform running ESPHome and the DSMR Component. Super cool! But there is a problem… the OBIS codes used in my country (Israel) are not the Dutch standard codes, and I couldn’t get the readings I wanted. So, I created (together with Gemini…) a simple YAML that parses out custom OBIS codes from the raw DSMR output and pushes them out as sensors. No need to use any extra libraries other than the standard DSMR Reader. I hope it will be useful to other people who want to read extra fields out of their DSMR-style P1 sensors.

Enjoy!

esphome:
  name: smartmeter
  friendly_name: Smart Meter

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino
    
light:
  - platform: esp32_rmt_led_strip
    id: my_light  
    rgb_order: GRB
    pin: GPIO48
    num_leds: 1
    chipset: ws2812
    name: "RGB LED"
    
# Enable logging
logger:
  level: INFO
  baud_rate: 0

# Enable Home Assistant API
api:
  encryption:
    key: "xxx"

ota:
  - platform: esphome
    password: "xxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Fallback Hotspot"
    password: "xxx"

captive_portal:
    
# Serial connection to the meter
uart:
  baud_rate: 115200
  data_bits: 8
  rx_buffer_size: 1500
  rx_pin:
    number: GPIO14
    inverted: true
    
  parity: NONE
  stop_bits: 1
  
# Regex parsing from UART
text_sensor:
  - platform: dsmr
    telegram:
      id: "telegram"
      internal: true
      name: "Raw DSMR Telegram"
      on_value:
        then:
          - lambda: |-
              std::string telegram_content = x;
              
              auto get_value = [&](const std::string& pattern_start, const std::string& pattern_end) -> optional<float> {
                size_t start_pos = telegram_content.find(pattern_start);
                if (start_pos == std::string::npos) {
                  return {};
                }
                start_pos += pattern_start.length();
                size_t end_pos = telegram_content.find(pattern_end, start_pos);
                if (end_pos == std::string::npos) {
                  return {};
                }
                std::string value_str = telegram_content.substr(start_pos, end_pos - start_pos);
                
                return parse_number<float>(value_str);
              };

              // Active Energy Consumption
              if (auto val = get_value("1-0:1.8.11(", "*kWh)")) {
                id(energy_consumption_t1).publish_state(*val);
              }
              if (auto val = get_value("1-0:1.8.13(", "*kWh)")) {
                id(energy_consumption_t2).publish_state(*val);
              }

              // Active Energy Production
              if (auto val = get_value("1-0:2.8.13(", "*kWh)")) {
                id(total_energy_production).publish_state(*val);
              }

              // Active Power
              if (auto val = get_value("1-0:1.7.0(", "*kW)")) {
                id(active_power_consumption).publish_state(*val);
              }
              if (auto val = get_value("1-0:2.7.0(", "*kW)")) {
                id(active_power_production).publish_state(*val);
              }
              
              // Active Power Consumption per Phase
              if (auto val = get_value("1-0:21.7.0(", "*kW)")) {
                id(active_power_consumption_phase1).publish_state(*val);
              }
              if (auto val = get_value("1-0:41.7.0(", "*kW)")) {
                id(active_power_consumption_phase2).publish_state(*val);
              }
              if (auto val = get_value("1-0:61.7.0(", "*kW)")) {
                id(active_power_consumption_phase3).publish_state(*val);
              }

              // Active Power Production per Phase
              if (auto val = get_value("1-0:22.7.0(", "*kW)")) {
                id(active_power_production_phase1).publish_state(*val);
              }
              if (auto val = get_value("1-0:42.7.0(", "*kW)")) {
                id(active_power_production_phase2).publish_state(*val);
              }
              if (auto val = get_value("1-0:62.7.0(", "*kW)")) {
                id(active_power_production_phase3).publish_state(*val);
              }

              // Voltage and Current per Phase
              if (auto val = get_value("1-0:32.7.0(", "*V)")) {
                id(voltage_phase1).publish_state(*val);
              }
              if (auto val = get_value("1-0:52.7.0(", "*V)")) {
                id(voltage_phase2).publish_state(*val);
              }
              if (auto val = get_value("1-0:72.7.0(", "*V)")) {
                id(voltage_phase3).publish_state(*val);
              }

              if (auto val = get_value("1-0:31.7.0(", "*A)")) {
                id(current_phase1).publish_state(*val);
              }
              if (auto val = get_value("1-0:51.7.0(", "*A)")) {
                id(current_phase2).publish_state(*val);
              }
              if (auto val = get_value("1-0:71.7.0(", "*A)")) {
                id(current_phase3).publish_state(*val);
              }

  # Individual template sensors that are published by the parser
sensor:
  - platform: template
    id: energy_consumption_t1
    name: "Energy Consumption (Tariff 1)"
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: template
    id: energy_consumption_t2
    name: "Energy Consumption (Tariff 2)"
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: template
    id: total_energy_consumption
    unit_of_measurement: "kWh"
    name: "Total Energy Consumption"
    device_class: energy
    state_class: total_increasing
    lambda: |-
      return id(energy_consumption_t1).state + id(energy_consumption_t2).state;


  - platform: template
    id: total_energy_production
    name: "Total Energy Production"
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: template
    id: active_power_consumption
    name: "Active Power Consumption"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement

  - platform: template
    id: active_power_production
    name: "Active Power Production"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement
    
  - platform: template
    id: voltage_phase1
    name: "Voltage (Phase 1)"
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

  - platform: template
    id: voltage_phase2
    name: "Voltage (Phase 2)"
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

  - platform: template
    id: voltage_phase3
    name: "Voltage (Phase 3)"
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

  - platform: template
    id: current_phase1
    name: "Current (Phase 1)"
    unit_of_measurement: "A"
    device_class: current
    state_class: measurement
    
  - platform: template
    id: current_phase2
    name: "Current (Phase 2)"
    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

  - platform: template
    id: current_phase3
    name: "Current (Phase 3)"
    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

  - platform: template
    id: active_power_consumption_phase1
    name: "Active Power Consumption (Phase 1)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement
      
  - platform: template
    id: active_power_consumption_phase2
    name: "Active Power Consumption (Phase 2)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement

  - platform: template
    id: active_power_consumption_phase3
    name: "Active Power Consumption (Phase 3)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement

  - platform: template
    id: active_power_production_phase1
    name: "Active Power Production (Phase 1)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement

  - platform: template
    id: active_power_production_phase2
    name: "Active Power Production (Phase 2)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement

  - platform: template
    id: active_power_production_phase3
    name: "Active Power Production (Phase 3)"
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement