Here is the code (I have no time for github sry)  //Arduino IDE 2.3.7

/*
  RIIO_TINETZ – ESP32 – M-Bus (TINETZ Kundenschnittstelle) -> MQTT

  - Reads segmented M-Bus long frames (0x68 ... 0x16), reassembles DLMS payload
  - Parses General-GLO-Ciphering APDU (0xDB 0x08 ...)
  - Handles sec_ctrl = 0x21 (Encryption-only, Auth not applied) by decrypting via AES-CTR (GCM-CTR)
  - Extracts COSEM Data-Notification (0x0F) and publishes OBIS values to MQTT
  - MQTT Watchdog toggles true/false every 30s
  - Adds SSD1306 128x64 I2C OLED debug screen
  - Sends M-Bus ACK (0xE5) after each valid long frame (CRC ok)
*/

#include <WiFi.h>
#include <MQTT.h>

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include "mbedtls/aes.h"
#include "mbedtls/gcm.h"
#include <math.h>

// ---------- Forward declarations (fix Arduino auto-prototype issues) ----------
struct AxdrValue;
class AxdrReader;

// ------------------------- USER CONFIG -------------------------

#define WIFI_SSID     "wifissd"
#define WIFI_PASSWORD "wifipwd"

static const char* MQTT_HOST = "mqtt host ip";
static const uint16_t MQTT_PORT = mqtt host port ;

// Base topics (KEEP EXACT)
static const char* TOPIC_BASE          = "tinetz/smartmeter";
static const char* TOPIC_STATUS_WD     = "tinetz/smartmeter/status/watchdog";

static const char* TOPIC_DEBUG_SYS     = "tinetz/smartmeter/debug/sys_title";
static const char* TOPIC_DEBUG_SC      = "tinetz/smartmeter/debug/sec_ctrl";
static const char* TOPIC_DEBUG_IC      = "tinetz/smartmeter/debug/invocation_counter";
static const char* TOPIC_DEBUG_DECFAIL = "tinetz/smartmeter/debug/decrypt_fail";
static const char* TOPIC_DEBUG_CIPHER  = "tinetz/smartmeter/debug/cipher_hex";

// Your DML key (hex, 16 bytes / 32 hex chars)
static const char* DML_KEY_HEX = "Benutzerschnittstelle key from TINETZ ";

// ------------------------- PIN CONFIG -------------------------

// ESP32 UART2 pins
static const int MBUS_RX_PIN = 16;
static const int MBUS_TX_PIN = 17;  // used for ACK 0xE5
static const uint32_t MBUS_BAUD = 2400;

// OLED I2C (SSD1306 128x64)
static const int OLED_SDA = 21;
static const int OLED_SCL = 22;
static const uint8_t OLED_ADDR = 0x3C;   // change to 0x3D if needed
static const int OLED_RESET = -1;

// ------------------------- MQTT/WIFI -------------------------

WiFiClient net;
MQTTClient mqtt(4096);

// OLED object
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);

// ------------------------- RUNTIME / DEBUG STATE -------------------------

static uint8_t g_dmlKey[16];

static unsigned long g_lastMbusFrameMs = 0;
static unsigned long g_lastMbusByteMs  = 0;
static uint32_t g_mbusFramesOk = 0;
static uint32_t g_mbusBadCrc   = 0;
static uint32_t g_mbusResets   = 0;

static uint32_t g_decryptFailCount = 0;
static unsigned long g_lastDecryptOkMs = 0;

static uint8_t g_lastSysTitle[8] = {0};
static uint8_t g_lastSecCtrl = 0;
static uint8_t g_lastInvCtr[4] = {0};

static String g_lastObis = "";
static String g_lastObisVal = "";

static unsigned long g_lastOledMs = 0;
static unsigned long g_lastSerialRestartMs = 0;

// ------------------------- HELPERS -------------------------

static bool hexNibble(char c, uint8_t& out) {
  if (c >= '0' && c <= '9') { out = (uint8_t)(c - '0'); return true; }
  if (c >= 'a' && c <= 'f') { out = (uint8_t)(10 + (c - 'a')); return true; }
  if (c >= 'A' && c <= 'F') { out = (uint8_t)(10 + (c - 'A')); return true; }
  return false;
}

static bool hexToBytes(const char* hex, uint8_t* out, size_t outLen) {
  size_t n = strlen(hex);
  if (n != outLen * 2) return false;
  for (size_t i = 0; i < outLen; i++) {
    uint8_t hi, lo;
    if (!hexNibble(hex[2*i], hi) || !hexNibble(hex[2*i+1], lo)) return false;
    out[i] = (uint8_t)((hi << 4) | lo);
  }
  return true;
}

static String...

Read more »