Looking for help using IPERL watermeter with ESPHome (ESP32/CC1101)

I have installed a ESP32 nodemcu with a CC1101 to read the wmbus data from my IPERL watermeter. In principle it seems to work but my ESPHome sensors are not updated.

I am using ESPHome 2025.2.2 with the Szczepan’s esphome custom component ( esphome-components/components/wmbus/wmbus.cpp at main · SzczepanLeon/esphome-components and an AES key from my water provider.

The ESPHome log contains this if it receives data from the iperl:

[10:04:56][V][rxLoop:167]: Have 56 bytes from CC1101 Rx, RSSI: -27 dBm LQI: 128
[10:04:56][D][mbus:035]: Received T1 A frame
[10:04:56][V][mbus:046]: Frame: 37271C9B273434D59659C38E6AC5935B2A744E635A596356599C652F43726A9D2564D99A36338BC59393C5C6B299A5A3D269A94DA5A99A55 (56) [RAW]
[10:04:56][VV][3of6:095]: Decode 3 out of 6 OK.
[10:04:56][V][mbus:053]: Frame: 1E44AE4C1100042268070EFC7A16001005D93C1E6FC951A61B23D527D46EA60BCAAF760FA9 (37) [with CRC]
[10:04:56][V][mbus:096]: Validating CRC for Block1
[10:04:56][V][crc:031]:     calculated: 0x0EFC, read: 0x0EFC
[10:04:56][V][mbus:116]: Validating CRC for Block2
[10:04:56][V][crc:031]:     calculated: 0xD46E, read: 0xD46E
[10:04:56][V][mbus:116]: Validating CRC for Block3
[10:04:56][V][crc:031]:     calculated: 0x0FA9, read: 0x0FA9
[10:04:56][V][mbus:063]: Frame: 1E44AE4C1100042268077A16001005D93C1E6FC951A61B23D527A60BCAAF76 (31) [without CRC]
[10:04:56][VV][wmbus:056]: Have data from RF ...
[10:04:56][V][Telegram.cpp:1131]: (wmbus) parseDLL @0 31
[10:04:56][V][Telegram.cpp:1178]: (wmbus) parseELL @10 21
[10:04:56][V][Telegram.cpp:1333]: (wmbus) parseNWL @10 21
[10:04:56][V][Telegram.cpp:1391]: (wmbus) parseAFL @10 21
[10:04:56][V][Telegram.cpp:2078]: (wmbus) parseTPL @10 21
[10:04:56][I][wmbus:104]: iperl [0x22040011] RSSI: -27dBm T: 1E44AE4C1100042268077A16001005D93C1E6FC951A61B23D527A60BCAAF76 (31) T1 A
[10:04:56][W][component:237]: Component wmbus took a long time for an operation (105 ms).
[10:04:56][W][component:238]: Components should block for at most 30 ms.

If I put a telegram and my key into the analyzer on https://wmbusmeters.org I’m getting this:

telegram=|1E44AE4C1100042268077A150010052F2F_04136CDC0300023B00002F2F2F2F|

Auto driver    : iperl
Similar driver : topaseskr 06/06
Using driver   : iperl 00/00
000   : 1e length (30 bytes)
001   : 44 dll-c (from meter SND_NR)
002   : ae4c dll-mfct (SEN)
004   : 11000422 dll-id (22040011)
008   : 68 dll-version
009   : 07 dll-type (Water meter)
010   : 7a tpl-ci-field (EN 13757-3 Application Layer (short tplh))
011   : 15 tpl-acc-field
012   : 00 tpl-sts-field (OK)
013   : 1005 tpl-cfg 0510 (AES_CBC_IV nb=1 cntn=0 ra=0 hc=0 )
015   : 2f2f decrypt check bytes (OK)
017   : 04 dif (32 Bit Integer/Binary Instantaneous value)
018   : 13 vif (Volume l)
019 C!: 6CDC0300 ("total_m3":253.036)
023   : 02 dif (16 Bit Integer/Binary Instantaneous value)
024   : 3B vif (Volume flow l/h)
025 C!: 0000 ("max_flow_m3h":0)
027   : 2F skip
028   : 2F skip
029   : 2F skip
030   : 2F skip

{
    "_":"telegram",
    "media":"water",
    "meter":"iperl",
    "name":"",
    "id":"22040011",
    "max_flow_m3h":0,
    "total_m3":253.036,
    "timestamp":"2025-03-23T08:04:30Z"
}

Sometimes I’m also receiving data that cannot be decoded. Maybe from another meter or some other device I guess.

[09:38:28][V][rxLoop:167]: Have 332 bytes from CC1101 Rx, RSSI: -97 dBm LQI: 194
[09:38:28][D][mbus:035]: Received T1 A frame
[09:38:28][V][mbus:041]: Frame: D0E2F4697E080830185D62122208890901B0D614C81BE001E028DCAD88942315EF84A1CB24410039A021084F81F96E09C681B000202713689FAA20FC8BF509DCEF9B4021050888C818838832343120585BF0C6808A30D7254321F2078A4032D50D030AE2505503023C1A94C1046025004933180ADD8C6A802A0B2E21444A323FE3A840D52040800611894412682469400509C1710600DD40D1B143A6D165104665D498F8D43741AAFB8F83A96D7115182B3E026321230BD88270A42F4280116A49D0C190432C8B70 [RAW]
[09:38:28][V][mbus:043]:        4AB3DA18F6AFC00B68996025C0F01AF500BC2EC90088195289FECA982E9D1A06860F770703D601E8C41E8872349A0EC55F270C93382C887E11054B14404BC745944623A116E951A34890476008080C2080411A791594602E22CA0EEC6090DE45E3513876064EC4053D18EE006B1CE20069E843C1832E01721C9DCBCCA434C621074E7318 (332) [RAW]
[09:38:28][V][3of6:083]: Decode 3 out of 6 failed..

So there are telegrams can be properly decoded. But all my ESPHome sensors are always unavailable and I cannot find out why.

This is my ESPHome .yaml:


substitutions:

  ## device settings
  device_name_short: "water-meter-esp"
  device_description: "Wasserzähler ESP32, IPERL"
  projectname: "IPERL 868.Watermeter"
  appversion: "1.0"

  ## all watermeters   wmid: "0"
  wmid: !secret watermeterId

  ## logger settings
  log_level: "VERY_VERBOSE"  # not that logging need memory, so in production mode use "WARN"
  log_wmbus: "VERY_VERBOSE" # Loglevel for wmbus meters component
  log_baudrate: "0" # 0 disable uart logger messages

## ----------------------------------------------------------------
## APPLICATION ESPHOME
## ----------------------------------------------------------------
esphome:
  name: ${device_name_short}
  comment: ${device_description}
  # Automatically add the mac address to the name
  # so you can use a single firmware for all devices
  name_add_mac_suffix: false
  project:
    name: ${projectname}
    version: ${appversion}
  build_path: ./build/${device_name_short}
  on_boot:
    priority: 200
    then:
      - globals.set:
          id: boot_counter
          value: !lambda "return id(boot_counter)+=1;"
      - logger.log:
          level: INFO
          tag: "system"
          format: "BOOTMESSAGE:${device_name_short} API is connected, Device ready!"
      - component.update: bootcounter
  on_shutdown:
    priority: 700
    then:
      - logger.log:
          level: ERROR
          tag: "system"
          format: "BOOTMESSAGE:${device_name_short} is down!"

esp32:
  board: esp32dev
  framework:
    type: arduino

## ----------------------------------------------------------------
## EXTERNAL COMPONENTS
## ----------------------------------------------------------------
external_components:

  # uses the latest version from SzczepanLeon
  # https://github.com/SzczepanLeon/esphome-components
  # You can make ESPHome check the repository every time by setting this option to 0s
  - source: github://SzczepanLeon/esphome-components@main
    refresh: 0s
    components: [wmbus]

## ----------------------------------------------------------------
## Global variables
## ----------------------------------------------------------------
globals:

  - id: boot_counter
    type: int
    restore_value: yes
    initial_value: "0"

  - id: last_value
    type: float
    restore_value: yes
    initial_value: "0.00"

## ---------------------------------------------------
## WIFI Settings
## ---------------------------------------------------
wifi:
  networks:
    - ssid: !secret ssid3_name
      password: !secret ssid3_pswd
      priority: 0
  domain: !secret domain

## ---------------------------------------------------
## mDNS Component
## ---------------------------------------------------
mdns:
  # if mDNS is disabled, they will no longer be able to automatically find your devices.
  disabled: false

captive_portal:

## ---------------------------------------------------
## LOGGER COMPONENT
## ---------------------------------------------------
logger:
  id: appslogger
  level: ${log_level}
  baud_rate: ${log_baudrate}
  logs:
    wmbus: ${log_wmbus}
    wMBus-lib: ${log_wmbus}

## ---------------------------------------------------
## OTA COMPONENT
## ---------------------------------------------------
ota:
  platform: esphome
  password: !secret ota_pswd

## ---------------------------------------------------
## COMPONENT WEBSERVER
## ---------------------------------------------------
web_server:
  port: 80
#  version: 2
#  js_url: !secret webserver_jsurl

api:
  encryption:
    key: !secret api_encryption_key

## ---------------------------------------------------
## SNTP COMPONENT
## ---------------------------------------------------
time:
  - platform: sntp
    id: time_sntp
    timezone: Europe/Berlin
    servers:
      - 0.at.pool.ntp.org
      - 0.pool.ntp.org
      - 1.pool.ntp.org
    on_time_sync:
      then:
        - logger.log:
            tag: "system"
            level: INFO
            format: "Synchronized sntp clock"


## ------------------------------------------------------------------
##           WMBUS CC1101 --> ESP32 az-delivery-devkit-v4
## ------------------------------------------------------------------
##
##
##                                                               o 1 (3.3V)
##                                                               |
##   ╭――x――x――x――x――x――x――x――x――x――x――x――x――x――x――x――x――x――x――x――o―╮
##   |                                                             |
##   |                                                             |
## - | 5v               az-delivery-devkit-v4                      | -- ANT
##   |                                                             |
##   |                          16 17 5  18 19               23    |
##   ╰――x――x――x――x――x――x――x――x――o――x――o――o――o――o――o――o――o――o――o――o―╯
##                              |  |  |  |  |                 |   |
##                              o  |  |  o  |                 |   ╰-o - 2 (GND)
##                              7  o  |  4  o                 o
##                            GDO0 6  | CLK 5                 3
##                               GD02 o    MISO              M0SI
##                                    8
##                                   CSN
##
## ------------------------------------------------------------------
wmbus:
  mosi_pin: GPIO23    ## SI:   braun
  miso_pin: GPIO19    ## SO:   grün
  clk_pin: GPIO18     ## SCLK: violett
  cs_pin: GPIO05      ## CSN:  orange
  gdo0_pin: GPIO16    ## GD00: gelb (rx)
  gdo2_pin: GPIO17    ## GD02: weiss (tx)

#  all_drivers: true
  log_all: true
  
#  frequency: 868.950

## ---------------------------------------------------
## SWITCHES
## ---------------------------------------------------
switch:
  # reset boot counter value
  - platform: template
    name: Device Boot Counter reset
    turn_on_action:
      then:
        - lambda: |-
            id(boot_counter) = 0;
            id(bootcounter).publish_state(id(boot_counter));
        - logger.log:
            level: WARN
            tag: "system"
            format: "${device_name_short} reset boot counter o.k!"
        - component.update: bootcounter

  - platform: restart
    name: "Restart"
    id: restart_switch

## ---------------------------------------------------
## SENSORS
## ---------------------------------------------------
sensor:
  - platform: wmbus
    # Meter ID (usually from sticker). Can be specified as decimal or hex.
    # only hex is working for my watermeter !
    # see: https://github.com/SzczepanLeon/esphome-components/issues/6
    # edit watermeterid in the secrets file
    meter_id: !secret watermeterId
    type: iperl
    key: !secret watermeter_key
    
#    add_prefix: true

    sensors:
      - name: "CC1101 LQI"
        field: "lqi"
        id: wmbus_cc1101_lqi
        entity_category: "diagnostic"
        unit_of_measurement: "lqi"
        state_class: "measurement"

      - name: "RSSI"
        field: "rssi"
        id: wmbus_cc1101_rssi
        unit_of_measurement: "dbm"

      - name: "Wasser Gesamt"
        field: "total"
        id: "water_total"
        unit_of_measurement: "m³"
        state_class: total_increasing
        device_class: "water"
        accuracy_decimals: 3
        on_value:
          then:
          - text_sensor.template.publish:
              id: cold_water_last_update
              state: !lambda 'return id(time_sntp).now().strftime("%Y-%m-%d %H:%M:%S");'

      - name: "Wasser Max Flow"
        field: "max_flow"
        id: "water_max_flow"
        unit_of_measurement: "m³h"
        state_class: measurement
        device_class: "water"
        accuracy_decimals: 3

  # Wifi quality RSSI, internal used to calculate the Wifi quality RSSI in percentage
  - platform: wifi_signal
    id: wifi_signal_db
    update_interval: 60s
    internal: true
    disabled_by_default: true

  # Wifi quality RSSI in percentage
  # Received Signal Strength (RSSI) is a measure of incoherent
  ## (raw) RF power in a channel.
  - platform: copy # Reports the WiFi signal strength in %
    source_id: wifi_signal_db
    name: "Device WLAN Signal"
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "%"
    entity_category: "diagnostic"

  # device boot counter
  - platform: template
    name: Device Boot counter
    id: bootcounter
    icon: mdi:counter
    accuracy_decimals: 0
    state_class: "measurement"
    entity_category: "diagnostic"
    lambda: return (id(boot_counter));

text_sensor:
  - platform: version
    name: "ESPHome Version"
  - platform: template
    name: "Wasserzähler Letztes Update"
    id: cold_water_last_update

I was not able to fix this and I got no support yet from the custom component developer. So I went for the nanoCUL solution (Arduino Nano + CC1101) connected via USB to HA and the Wmbusmeters (W-MBus to MQTT) add-on. This now works fine for me.

The key learning regarding my Sensus IPERL watermeter configuration is that it sends its data every 60 minutes but ONLY if the meter reading changed ! This was initially kind of confusing until I realized how it works.