Making my power and gas meters smart, I tried to read my gas meter (BK-G4) with a reed contact.
I wasn’t really happy with this approach with the reed sensor sometimes bouncing and I’m not experienced enough to build a hardware debouncer.
Another question I had is what happens when the gas meter stays for a couple of time with the magnet near the reed contact (no more warm water needed, counter stays at “0” - will the reed really read once or will it read more often?
So I decided to go with a magnetometer. I used the GY-271 which ships for around 3 €/$, maybe even cheaper from Ali.
After mounting (I used a 3d printed case fittet for relays) I first looked at the history graph on all 3 axis.
I decided to go with the X axis and set a global variable “high” to true whenever it reads more than 50 microtesla (look at the graphs) and to false whenever it goes below zero.
I increment the gas counter by 0.01 on every spike (gas meter says so, since the magnet is in the third decimal place).
I added another sensor to calculate from m³ to kWh (depends on your actual place and situation, you have to look up these variables in your gas invoices), and another sensor to show the gas flow in the last minute.
So far it works extremely reliable.
Bonus:
Since my gas meter is far away I used the olimex PoE board and used GPIO 2 and 3.
Another side note: The GY-271 is connected to the ESP with a 6 meter unshielded four pole cable which also works great.
Last side note: The ESP also reads out my power meter with OBIS protocol on the RX/TX with a 15 meter CAT5 cable which also works perfect.
esphome:
name: olimex
platform: ESP32
board: esp32-poe
logger:
# baud_rate: 0
# hardware_uart: UART2
level: DEBUG
api:
ota:
substitutions:
devicename: "energiezaehler"
upper_devicename: "Energiezaehler"
friendly_name: "Energiezaehler"
i2c:
sda: 2
scl: 3
scan: true
id: bus_a
globals:
- id: gas_counter_total
type: float
restore_value: yes
initial_value: '0'
- id: gas_counter
type: long
restore_value: no
initial_value: '0'
- id: gas_high
type: bool
restore_value: no
initial_value: 'false'
interval:
- interval: 5000ms
then:
- lambda: |-
if (id(hmc5883lx).state >= 50 && !id(gas_high)) {
id(gas_counter_total) += 0.01;
id(gas_counter) += 1;
id(gas_high) = true;
} else if (id(hmc5883lx).state <= -2 && id(gas_high)) {
id(gas_high) = false;
}
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk_mode: GPIO17_OUT
phy_addr: 0
power_pin: GPIO12
time:
- platform: homeassistant
id: homeassistant_time
web_server:
port: 80
binary_sensor:
- platform: status
name: "${friendly_name} - Status"
device_class: connectivity
uart:
# (obis reader, not topic here)
sensor:
- platform: hmc5883l
# address: 0x68
field_strength_x:
name: "${friendly_name} HMC5883L X"
id: hmc5883lx
field_strength_y:
name: "${friendly_name} HMC5883L Y"
id: hmc5883ly
field_strength_z:
name: "${friendly_name} HMC5883L Z"
id: hmc5883lz
range: 250uT
oversampling: 8
update_interval: 1s
heading:
name: "${friendly_name} HMC5883L Heading"
- platform: template
name: "${friendly_name} Gas Durchfluss"
lambda: |-
int temp = id(gas_counter);
id(gas_counter) -= temp;
return temp;
update_interval: 60s
unit_of_measurement: "m³/min"
- platform: template
name: "${friendly_name} Gas Gesamt"
lambda: |-
return id(gas_counter_total);
update_interval: 5s
unit_of_measurement: "m³"
accuracy_decimals: 2
icon: 'mdi:fire'
device_class: gas
state_class: total_increasing
- platform: template
name: "${friendly_name} Gas kWh"
# Gasvolumen in m³ x Zustandszahl x Brennwert = Gasverbrauch in kWh
# Zustandszahl: 0.8934
# Brennwert: 11.274
filters:
lambda: |-
return (id(gas_counter_total) * (10.0721916));
update_interval: 5s
unit_of_measurement: "kWh"
accuracy_decimals: 2
icon: 'mdi:fire'
device_class: energy
state_class: total_increasing
text_sensor:
- platform: version
name: "${friendly_name} - Version"
icon: mdi:cube-outline
Thanks to @haufes Water / Gas Meter Monitoring Via Magnetometer - Sine Wave to Pulse Issue - #6 by haufes