Skip to content

Instantly share code, notes, and snippets.

@k0ff33
Created March 22, 2026 23:51
Show Gist options
  • Select an option

  • Save k0ff33/39b9aec2c35b33f96c7a65b85b89fc83 to your computer and use it in GitHub Desktop.

Select an option

Save k0ff33/39b9aec2c35b33f96c7a65b85b89fc83 to your computer and use it in GitHub Desktop.
ESPhome configuration for wmbus-reader on Lilygo T3 LoRa32 V1.6.1
esphome:
name: wmbus-reader
friendly_name: wM-Bus Reader
esp32:
board: ttgo-lora32-v1
framework:
type: esp-idf
advanced:
loop_task_stack_size: 16384
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "wMBus Fallback"
password: "wmbus-reader"
captive_portal:
api:
time:
- platform: homeassistant
ota:
- platform: esphome
logger:
level: DEBUG
baud_rate: 115200
external_components:
- source: github://k0ff33/esphome-components@main
components: [wmbus_radio, wmbus_common, wmbus_meter]
# ── SPI bus (SX1278, LilyGo T3 v1.6.1) ──────────────────────────────────────
spi:
clk_pin: GPIO5
mosi_pin: GPIO27
miso_pin: GPIO19
# ── wM-Bus common: active drivers ────────────────────────────────────────────
wmbus_common:
drivers:
- apator162
- amiplus
# ── wM-Bus radio ─────────────────────────────────────────────────────────────
wmbus_radio:
radio_type: SX1276 # SX1278 (868 MHz) is the same driver as SX1276
cs_pin: GPIO18
irq_pin: GPIO33 # DIO1 — FIFO-not-empty interrupt; DIO0 (GPIO26) is RxDone/PayloadReady only
reset_pin: GPIO23
has_tcxo: false # T3 v1.6.1 has no TCXO
# Scan mode: logs every frame so you can discover meter IDs.
# Paste the hex data at https://wmbusmeters.org/analyze/ to decode and find your meter ID.
on_frame:
- then:
- logger.log:
format: "RSSI: %ddBm T: %s (%d)"
args: [frame->rssi(), frame->as_hex().c_str(), frame->data().size()]
# ── Meter definitions ─────────────────────────────────────────────────────────
wmbus_meter:
- id: water_meter
meter_id: 0x00000000
type: apator162
key: "00000000000000000000000000000000"
mode:
- T1
- C1
- id: garden_water_meter
meter_id: 0x00000000
type: apator162
key: "00000000000000000000000000000000"
mode:
- T1
- C1
- id: elec_meter
meter_id: 0x00000000
type: amiplus
key: !secret pge_key
mode:
- T1
- C1
# ── Sensors ───────────────────────────────────────────────────────────────────
sensor:
- platform: wmbus_meter
parent_id: water_meter
id: water_total
field: total_m3
name: "Water Total"
state_class: total_increasing
device_class: water
unit_of_measurement: "m³"
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: garden_water_meter
id: garden_water_total
field: total_m3
name: "Garden Water Total"
state_class: total_increasing
device_class: water
unit_of_measurement: "m³"
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: elec_meter
id: elec_power
field: current_power_consumption_kw
name: "Power"
device_class: power
state_class: measurement
unit_of_measurement: "kW"
accuracy_decimals: 3
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: elec_meter
id: elec_total
field: total_energy_consumption_kwh
name: "Energy Total"
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: elec_meter
id: elec_tariff1
field: total_energy_consumption_tariff_1_kwh
name: "Energy Tariff 1 (Day)"
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: elec_meter
id: elec_tariff2
field: total_energy_consumption_tariff_2_kwh
name: "Energy Tariff 2 (Night)"
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
filters:
- heartbeat: 60s
# ── Diagnostics ──
- platform: wmbus_meter
parent_id: water_meter
id: water_rssi
field: rssi_dbm
name: "Water RSSI"
device_class: signal_strength
state_class: measurement
unit_of_measurement: "dBm"
entity_category: diagnostic
filters:
- heartbeat: 60s
- platform: wmbus_meter
parent_id: garden_water_meter
id: garden_water_rssi
field: rssi_dbm
name: "Garden Water RSSI"
device_class: signal_strength
state_class: measurement
unit_of_measurement: "dBm"
entity_category: diagnostic
filters:
- heartbeat: 60s
- platform: wifi_signal
id: wifi_signal_db
name: "WiFi Signal"
entity_category: diagnostic
update_interval: 60s
text_sensor:
- platform: wifi_info
ip_address:
id: wifi_ip
# ── Display: 0.96" SSD1306 128x64 OLED ───────────────────────────────────────
i2c:
sda: GPIO21
scl: GPIO22
frequency: 400kHz
font:
- file: "gfonts://Roboto Mono"
id: f10
size: 10
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
address: 0x3C
update_interval: 5s
lambda: |-
// Row 0 — WiFi IP
if (id(wifi_ip).state != "") {
it.printf(0, 0, id(f10), "IP: %s", id(wifi_ip).state.c_str());
} else {
it.print(0, 0, id(f10), "WiFi: connecting...");
}
// Row 1 — WiFi signal strength
if (!isnan(id(wifi_signal_db).state)) {
it.printf(0, 12, id(f10), "WiFi: %d dBm", (int)id(wifi_signal_db).state);
} else {
it.print(0, 12, id(f10), "WiFi: ---");
}
// Row 2 — Water total
if (!isnan(id(water_total).state)) {
it.printf(0, 24, id(f10), "W: %.3f m3", id(water_total).state);
} else {
it.print(0, 24, id(f10), "Water: scanning...");
}
// Row 3 — Garden water total
if (!isnan(id(garden_water_total).state)) {
it.printf(0, 36, id(f10), "G: %.3f m3", id(garden_water_total).state);
} else {
it.print(0, 36, id(f10), "Garden: scanning...");
}
// Row 4 — Current power / Energy
if (!isnan(id(elec_power).state)) {
it.printf(0, 48, id(f10), "%.2fkW %.0fkWh", id(elec_power).state, id(elec_total).state);
} else {
it.print(0, 48, id(f10), "Power: scanning...");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment