Skip to content

Arduino / ESP32

The WattWächter TTL is a pure IR reading head: it outputs your meter's data stream 1:1 as a TTL serial signal. On a microcontroller such as the ESP32 you only need to read this stream on a UART interface and decode it.

Most modern meters (eHZ, smart meter gateways) send their data in the SML format (Smart Message Language) at 9600 baud, 8N1. For this guide we use the ready-made SML-Parser library, which decodes the stream byte by byte and verifies the CRC checksum automatically.

How the communication works

Most meters send their telegram on their own at regular intervals (push) – for those, the receive line (green / RXD) is sufficient for read-out. The yellow TX line is only needed for the remaining meters that have to be requested to send.

Meter prerequisites

For the meter to send the full instantaneous values (power, phases), the PIN usually has to be disabled and the extended info mode (Inf → On) enabled. You obtain the PIN from your grid operator.


Wiring

The four wires of the WattWächter TTL connect 1:1 to the ESP32 (the RX/TX crossover is already done on the reading head's circuit board).

Wire (TTL) Function ESP32 pin
Brown VCC (3–5 V) 3V3
Green RXD (data) GPIO16 (RX2)
Yellow TXD GPIO17 (TX2) — optional
White GND GND

Wiring WattWächter TTL to ESP32

The wire colors are shown in the diagram: brown → VCC, green → RXD, yellow → TXD (dashed = optional), white → GND.

ESP8266 / D1 Mini

The ESP8266 has only one full hardware UART, which is shared with the USB-to-serial converter. Read the meter data there via Serial (RX = GPIO3) and send debug output via Serial1 (TX = GPIO2). SoftwareSerial is usually too slow at 9600 baud and leads to reception errors.


Option A — Arduino sketch (SML-Parser)

This option reads the most important values directly within the Arduino framework – ideal as a building block for your own projects.

Install the library

Open Tools → Manage Libraries…, search for SML-Parser (by olliiiver) and install it.

In platformio.ini:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
    olliiiver/SML Parser@^0.29

Sketch

#include <Arduino.h>
#include "sml.h"   // "SML-Parser" library by olliiiver

// --- UART to the WattWächter TTL -------------------------------------------
// ESP32 hardware UART2: RX2 = GPIO16, TX2 = GPIO17
#define TTL_RX_PIN 16   // -> green wire (RXD) of the WattWächter TTL
#define TTL_TX_PIN 17   // -> yellow wire (TXD), only needed for meters you must request
#define TTL_BAUD   9600

HardwareSerial MeterSerial(2);  // UART2

// --- Values we want to read from every SML telegram ------------------------
double importWh = -1;   // 1-0:1.8.0   energy drawn from grid     (Wh)
double exportWh = -1;   // 1-0:2.8.0   energy fed into grid        (Wh)
double powerW   = -1;   // 1-0:16.7.0  current active power        (W)

void handleImport() { smlOBISWh(importWh); }
void handleExport() { smlOBISWh(exportWh); }
void handlePower()  { smlOBISW(powerW); }

// OBIS code (6 bytes) -> matching handler function
typedef struct {
  const unsigned char OBIS[6];
  void (*Handler)();
} OBISHandler;

OBISHandler handlers[] = {
  {{ 0x01, 0x00, 0x01, 0x08, 0x00, 0xff }, &handleImport}, // 1-0:1.8.0   import (Wh)
  {{ 0x01, 0x00, 0x02, 0x08, 0x00, 0xff }, &handleExport}, // 1-0:2.8.0   export (Wh)
  {{ 0x01, 0x00, 0x10, 0x07, 0x00, 0xff }, &handlePower},  // 1-0:16.7.0  active power (W, signed)
  {{ 0x01, 0x00, 0x0f, 0x07, 0x00, 0xff }, &handlePower},  // 1-0:15.7.0  active power (magnitude) – fallback
  {{ 0, 0 }}
};

void setup() {
  Serial.begin(115200);
  MeterSerial.begin(TTL_BAUD, SERIAL_8N1, TTL_RX_PIN, TTL_TX_PIN);
  Serial.println(F("WattWaechter TTL reader started"));
}

void loop() {
  while (MeterSerial.available() > 0) {
    unsigned char c = MeterSerial.read();
    sml_states_t state = smlState(c);

    // A list inside the telegram finished:
    // check whether it carried one of the OBIS values we want.
    if (state == SML_LISTEND) {
      for (uint8_t i = 0; handlers[i].Handler != 0; i++) {
        if (smlOBISCheck(handlers[i].OBIS)) {
          handlers[i].Handler();
          break;
        }
      }
    }

    // Full telegram received and CRC verified -> print the values.
    if (state == SML_FINAL) {
      Serial.printf("Import:  %.3f kWh\n", importWh / 1000.0);
      Serial.printf("Export:  %.3f kWh\n", exportWh / 1000.0);
      Serial.printf("Power:   %.0f W\n\n", powerW);
    }
  }
}

Reading additional values

Simply extend the handlers table with more OBIS codes. The convenience functions smlOBISW() (watts), smlOBISVolt(), smlOBISAmpere() and smlOBISHertz() already return the value correctly scaled. Examples of common OBIS codes can be found under Additional OBIS codes.


If the ESP32 is going to be integrated into Home Assistant anyway, ESPHome is the fastest route: the SML decoding is already built in as a component, so you don't have to write any code.

uart:
  id: uart_meter
  rx_pin: GPIO16          # green wire (RXD) of the WattWächter TTL
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

sml:
  id: meter_sml
  uart_id: uart_meter

sensor:
  - platform: sml
    name: "Total import"
    sml_id: meter_sml
    obis_code: "1-0:1.8.0"
    unit_of_measurement: kWh
    accuracy_decimals: 3
    device_class: energy
    state_class: total_increasing
    filters:
      - multiply: 0.0001   # adjust scaling to your meter (see logs)
  - platform: sml
    name: "Total export"
    sml_id: meter_sml
    obis_code: "1-0:2.8.0"
    unit_of_measurement: kWh
    accuracy_decimals: 3
    device_class: energy
    state_class: total_increasing
    filters:
      - multiply: 0.0001
  - platform: sml
    name: "Current power"
    sml_id: meter_sml
    obis_code: "1-0:16.7.0"
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power
    state_class: measurement

Check the scaling factor

The ESPHome sml component returns the raw telegram value. The required multiply factor depends on the meter. Temporarily enable logger: level: VERY_VERBOSE, compare the output value with the reading on the meter and adjust the factor.


Troubleshooting

Problem Possible cause / solution
No data received Reading head not positioned correctly over the IR diode; green wire (RXD) not connected to the RX pin
Only energy counters, no power/phases Disable the PIN and set Inf → On on the meter
Checksum error / Unexpected byte Wrong baud rate/parity – check 9600 8N1; on the ESP8266 use the hardware UART instead of SoftwareSerial
Values off by a factor of 10/100 Scaler not taken into account – adjust multiply in ESPHome