ESPHome powered P1 meter

For a long time I was avoiding ESPHome on my esp-based P1 readers. Not that it’s bad, au contraire, I love it. It was my lack of knowledge in getting it to work. I tried it, didn’t work, so I “left it on the shelf”.

Until now …

Esp-link was for me the best way. It’s exactly the same thing as an USB cable, only via tcp. Personally I keep using tcp, as I use dsmr-reader as main logging tool. For many I’ve noticed that Home Assistant is enough (and that’s fine). For those I wanted a better/easier way to connect the reader to Home Assistant.

Luckily an important person within the Home Assistant team pointed to nldroid on GitHub who had it working the way I wanted it the first time. He has made a custom component CustomP1UartComponent. He explained it perfectly and without issues it worked straight away 😃

You need the library dsmr_p1_sensor.h and the configuration (all documented on his GitHub).

The config yaml:

esphome:
  name: esp_dsmr
  platform: ESP8266
  board: d1_mini
  includes:
    - dsmr_p1_uart.h
  libraries:
    - "Dsmr"

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

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

captive_portal:

# Enable logging
logger:
  level: DEBUG
  esp8266_store_log_strings_in_flash: False

# Enable Home Assistant API
api:
  password: ""

ota:
  password: ""
  
uart:
  - rx_pin: D2
    baud_rate: 115200
    id: uart_bus  

sensor:
  - platform: custom
    lambda: |-
      auto dsmr_p1_sensor = new CustomP1UartComponent(id(uart_bus));
      App.register_component(dsmr_p1_sensor);
      return {dsmr_p1_sensor->s_energy_delivered_tariff1, dsmr_p1_sensor->s_energy_delivered_tariff2, dsmr_p1_sensor->s_energy_returned_tariff1, dsmr_p1_sensor->s_energy_returned_tariff2, dsmr_p1_sensor->s_power_delivered, dsmr_p1_sensor->s_power_returned, dsmr_p1_sensor->s_voltage_l1, dsmr_p1_sensor->s_voltage_l2, dsmr_p1_sensor->s_voltage_l3, dsmr_p1_sensor->s_current_l1, dsmr_p1_sensor->s_current_l2, dsmr_p1_sensor->s_current_l3, dsmr_p1_sensor->s_power_delivered_l1, dsmr_p1_sensor->s_power_delivered_l2, dsmr_p1_sensor->s_power_delivered_l3, dsmr_p1_sensor->s_power_returned_l1, dsmr_p1_sensor->s_power_returned_l2, dsmr_p1_sensor->s_power_returned_l3, dsmr_p1_sensor->s_gas_device_type, dsmr_p1_sensor->s_gas_valve_position, dsmr_p1_sensor->s_gas_delivered};
    sensors:
    - name: "Consumption Low Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3
    - name: "Consumption High Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3  
    - name: "Return Low Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3
    - name: "Return High Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3  
    - name: "Actual Consumption Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Actual Delivery Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Instant Voltage L1 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Voltage L2 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Voltage L3 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Current L1 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Instant Current L2 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Instant Current L3 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Power Delivered L1 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Delivered L2 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Delivered L3 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L1 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L2 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L3 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Gas device type Sensor"
    - name: "Gas valve position Sensor"  
    - name: "Gas Meter M3 Sensor"
      unit_of_measurement: m3
      accuracy_decimals: 3 

Adding TCP server functionality

Ok, it is working perfectly, still I wanted the option to connect via TCP/Telnet. Luckily I had a component seen on GitHub from Oxan van Leeuwen. He made a custom component stream_server.cpp and stream_server.h.

The needed config is shown below:

esphome:
  # ...
  includes:
    - stream_server.h
    - stream_server.cpp

uart:
  id: uart_bus
  #  ...
  
custom_component:
  - lambda: |-
      auto stream_server = new StreamServerComponent(id(uart_bus));
      return {stream_server};

So, can those two be combined?

Yes it can 🥳

I ran in to some “issues”. Like WiFi settings. I wanted it to be plug & play, so no WiFi config and starting with Hotspot. Connect to the Hotspot, and there join it to your own wireless network. The ssid couldn’t be empty, so for formality I entered there “dummy_ssid”. A non existing network. Therefor it wil start automatically the hotspot after several tries (which will fail as the network doesn’t exist).

Update 15 December 2020:

It seems that if you’re not using ssid, but network (with no network defined) that it goes straight into hotspot (jay, success!). Yet now it is not showing the list of scanned networks, only the option to fill in the ssid and password/secret.

The code as it is now:

esphome:
  name: de_slimme_meter
  platform: ESP8266
  board: d1_mini
  includes:
    - dsmr_p1_uart.h
    - stream_server.h
    - stream_server.cpp
  libraries:
    - "Dsmr"

wifi:
  networks:

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "De Slimme Meter"
    password: ""

captive_portal:

web_server:
  port: 80
  
# Enable logging
logger:
  level: DEBUG
  esp8266_store_log_strings_in_flash: False

# Enable Home Assistant API
api:
  password: ""

ota:
  password: ""

uart:
  - rx_pin: D7
    baud_rate: 115200
    id: uart_p1
  - tx_pin: D0
    rx_pin: D1
    baud_rate: 115200

custom_component:
  - lambda: |-
      auto stream_server = new StreamServerComponent(id(uart_p1));
      return {stream_server};

sensor:
  - platform: custom
    lambda: |-
      auto dsmr_p1_sensor = new CustomP1UartComponent(id(uart_p1));
      App.register_component(dsmr_p1_sensor);
      return {dsmr_p1_sensor->s_energy_delivered_tariff1, dsmr_p1_sensor->s_energy_delivered_tariff2, dsmr_p1_sensor->s_energy_returned_tariff1, dsmr_p1_sensor->s_energy_returned_tariff2, dsmr_p1_sensor->s_power_delivered, dsmr_p1_sensor->s_power_returned, dsmr_p1_sensor->s_voltage_l1, dsmr_p1_sensor->s_voltage_l2, dsmr_p1_sensor->s_voltage_l3, dsmr_p1_sensor->s_current_l1, dsmr_p1_sensor->s_current_l2, dsmr_p1_sensor->s_current_l3, dsmr_p1_sensor->s_power_delivered_l1, dsmr_p1_sensor->s_power_delivered_l2, dsmr_p1_sensor->s_power_delivered_l3, dsmr_p1_sensor->s_power_returned_l1, dsmr_p1_sensor->s_power_returned_l2, dsmr_p1_sensor->s_power_returned_l3, dsmr_p1_sensor->s_gas_device_type, dsmr_p1_sensor->s_gas_valve_position, dsmr_p1_sensor->s_gas_delivered};
    sensors:
    - name: "Consumption Low Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3
    - name: "Consumption High Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3  
    - name: "Return Low Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3
    - name: "Return High Tarif Sensor"
      unit_of_measurement: kWh
      accuracy_decimals: 3  
    - name: "Actual Consumption Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Actual Delivery Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Instant Voltage L1 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Voltage L2 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Voltage L3 Sensor"
      unit_of_measurement: V
      accuracy_decimals: 3      
    - name: "Instant Current L1 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Instant Current L2 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Instant Current L3 Sensor"
      unit_of_measurement: A
      accuracy_decimals: 3      
    - name: "Power Delivered L1 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Delivered L2 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Delivered L3 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L1 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L2 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Power Returned L3 Sensor"
      unit_of_measurement: W
      accuracy_decimals: 3      
      filters:
        - multiply: 1000
    - name: "Gas device type Sensor"
    - name: "Gas valve position Sensor"  
    - name: "Gas Meter M3 Sensor"
      unit_of_measurement: m3
      accuracy_decimals: 3

Room for improvement?

Yes there is. At time of writing, the hotspot will start after one minute when it is not connecting to a wireless network. I wish this to be straight away. No minute delay. This I will look into and try to get it done ✅

Well as of the update of 15 December, it goes straight into hotspot mode, yet without the list of scanned devices. I’ve seen that list and I want that list, so still room for improvement.

12 comments

  1. Geert

    Many thanks for this clear documentation.
    So, if I would like to use the HomeAssistant DSMR add-in, I would only need the TCP server functionality as HA does the ‘decoding’. Is that correct ?
    What would be the advantage to make the ESP do this ?

    1. Marcel

      Hi, you don’t need the TCP-server if you’re using ESPHome integration with Home Assistant 😉 I added it to give a choice, one device for multiple platforms. For you, just pick what you need 😉

      1. Geert

        Hi Marcel,
        but then you don’t use the home assistant DSMR integration ? You get the sensor data directly from the ESP, correct ?
        Indeed, this is easier… You know it support the Belgian meters ?

        1. Marcel

          I use dsmr-reader, and that’s integrated in Home Assistant. I like it that you can compare dates, months and years … something that’s not available in HA. So yeah, I personally don’t use the ESPHome integration. It is supported for Belgian (Fluvius) meters. Yet I’m not sure if all data is available as Belgium uses some other ID’s. I’m working on an all-in-one idea, NL, BE, and other possible variations.

  2. Bob van Mierlo

    Will flashing with Esphome brick the possibility to use DSMR reader?
    I have DSMR reader linked to esp-link on it’s IP and port 23, is there any way to keep using this with esphome flashed to it?

    1. Marcel

      If you’re using both the dsmr_p1 code and stream_server, you should be able to use both. I can’t guaranty is for 100% as I’ve not tested it fully…

      includes:
      - dsmr_p1_uart.h
      - stream_server.h
      - stream_server.cpp

      In stream_server.h at the bottom you’ll see the code

      Stream *stream_{nullptr};
      AsyncServer server_{0};
      uint16_t port_{23};
      std::vector recv_buf_{};
      std::vector> clients_{};

      Note “uint16_t port_{23};” … by default there is entered an 8000-range port… change that to 23, than it should be working.

      Feel free to play around, you won’t brick it, you can always flash it back to esp-link 😉

  3. Rob

    Hallo, ik heb de DSRM Reader add-on in Home Assistant en een D1 Mini met ESP-Easy in de meterkast die het telegram stuurt. Werkt prima. Maar ik wil graag datzelfde regelen via ESPHome. Volgens mij heb ik alleen het telegram nodig, dus geen sensoren want die heeft DSRM Reader al via MQTT.
    Heb ik dan alleen de custom component met de stream nodig?
    En mijn hardware is zo dat de data van de meter op de RX pin binnenkomt, dus ik denk dat ik moet invullen rx_pin: RX
    Heb ik het een beetje goed begrepen?

    1. Marcel

      Als je dsmr reader gebruikt, heb je helemaal geen andere manieren/tools nodig. Wat je dan het beste kan doen is de dsmr-integratie doen in Home Assistant. Dan krijg je alle data in HA en log je alles binnen (in mijn ogen de beste keuze, gebruik ik ook). Je meter dubbel in HA zetten zou ik niet doen. Beantwoord dat je vraag?

      1. Rob

        Ik heb DSRM Reader al werkend in HA, wil daar ook niets aan veranderen.
        Ik wil de huidige Wemos die op ESP-Easy draait vervangen door een Wemos die ESPHome draait.
        De vraag is of jouw yaml in ESPHome hetzelfde telegram stuurt als de huidige.

        Dit is het huidige telegram:

        1-3:0.2.8(42)
        0-0:1.0.0(210214132834W)
        0-0:96.1.1(4530303035303031363930333135323134)
        1-0:1.8.1(014587.052*kWh)
        1-0:2.8.1(000000.000*kWh)
        1-0:1.8.2(012752.030*kWh)
        1-0:2.8.2(000000.000*kWh)
        0-0:96.14.0(0001)
        1-0:1.7.0(00.753*kW)
        1-0:2.7.0(00.000*kW)
        0-0:96.7.21(00002)
        0-0:96.7.9(00000)
        1-0:99.97.0(0)(0-0:96.7.19)
        1-0:32.32.0(00000)
        1-0:52.32.0(00000)
        1-0:72.32.0(00001)
        1-0:32.36.0(00000)
        1-0:52.36.0(00000)
        1-0:72.36.0(00000)
        0-0:96.13.1()
        0-0:96.13.0()
        1-0:31.7.0(002*A)
        1-0:51.7.0(001*A)
        1-0:71.7.0(002*A)
        1-0:21.7.0(00.351*kW)
        1-0:41.7.0(00.016*kW)
        1-0:61.7.0(00.385*kW)
        1-0:22.7.0(00.000*kW)
        1-0:42.7.0(00.000*kW)
        1-0:62.7.0(00.000*kW)
        !499F

        1. Marcel

          Ja, dat gaat wel werken, maar de vraag is: Waarom ESPHome? Als je DSMR-reader als hoofdlogger gebruikt, heb je genoeg aan esp-link (of elk ander soortgelijk functionaliteit). Waarom de esp12 meer belasten terwijl je daar geen gebruik van maakt? Mijn advies: gebruik esp-link.

          1. Rob

            Ik wil graag over naar ESPHome, omdat ik meerdere nodes heb die allemaal via ESPHome lopen.
            Alleen deze ene is een buitenbeentje, vandaar dat ik die ook in ESPHome wil hebben.

          2. Marcel

            Maar je wilt ook blijven loggen met dsmr-reader? Als je geen dsmr-reader had gehad, had ik je volledig begrepen. Maar je zegt dat je dsmr-reader gebruikt (en ik neem aan dat je dat blijft gebruiken?)

Leave a Reply

Your email address will not be published. Required fields are marked *