Gaszähler für Gasuhr mit Magnet

u5zzug

Active member
ist jemand daran interessiert?
Nachdem das mit einem Reedkontakt nie funktionierte, habe ich es letztes Jahr in ESPHome mit einem
Magnetometer umgesetzt.
 

u5zzug

Active member
Verwendet wurde ein ESP8266 mit einem Dallas Temperatursensor (ich wollte den Gasverbrauch mit der Temperatur verrechnen, aber ich habe keine passenden Zustandszahlen gefunden und so heftig ändert sich die Temperatur auch nicht) und ein
HMC5883L Magnetometer, dass sich als QMC5883L entpuppte. Die haben verschiedene Adressen und Ablesewerte.

In ESPHome kann mas substitutions verwenden, das sind Variablen.
Außerdem kan man mit packages: Dateien mit für jedes Gerät benötigtem Code einbinden.
DIe Ordner und Dateien muss man händisch anlegen Passwörter u.ä stehen wie bei HA in einer secrets.yaml.

Das ist die Konfiguration für den Gaszähler.
YAML:
#######################################################################
# Substitutions - use like $substitution_key or ${substitution_key}
#######################################################################
substitutions:
  # Project Name, upper/lowercase characters, digits and underscores.
  # Used as: hostname, mdns name, folder name
  project_name: 'esp-wh'
  project_id: 'esp_wh'

  # Used as: AP SSID, Common (Wifi, Uptime, Switch) Sensors
  friendly_name: 'esp Waschhaus'

  # Wifi Configuration
  wifi_ssid: !secret wifi_ssid
  wifi_password: !secret wifi_password
  static_ip: 192.168.1.161

  # AP (Access Point) Configuration
  ap_password: !secret ap_password
  ap_channel: '6'
  ap_timeout: '5min'

  # API Configuration
  api_password: !secret api_password

  # OTA Configuration
  ota_password: !secret ota_password

  # Log Level
  log_level: DEBUG

  # which sensor to use for puls detection
  magnetometer: "${project_id}_qmc5883ly"

#######################################################################
# Device config
#######################################################################
esphome:
  name: ${project_name}

esp8266:
  board: d1_mini

#######################################################################
# Include common config
#######################################################################
packages:
  common: !include common/common.yaml
  wifi_sensors: !include common/wifi.diag.yaml
  uptime: !include common/uptime.diag.yaml

preferences:
  flash_write_interval: 3min

i2c:
  scan: true        # Default true
  frequency: 100kHz # Default 50kHz. Values: 10kHz, 50kHz, 100kHz, 200kHz, … 800kHz

# Dallas Temp. Sensoren, Dreibein
dallas:
  - pin: D4

# global variables
globals:
   - id: gas_counter_total
     type: double
     restore_value: no
#     initial_value: '2717.94'
   - id: gas_counter
     type: int
     restore_value: no
     initial_value: '0'
   - id: gas_high
     type: bool
     restore_value: no
     initial_value: 'false'
   - id: magnetometer_last_value
     type: int
     restore_value: no
   - id: heating
     type: bool
     restore_value: no
   - id: heating_paused
     type: bool
     restore_value: no

# run actions at fixed time intervals
interval:
  - interval: 5s
    then:
    # convert magnetometer values to boolean gas_hight for counting pulses.
    # adapt numbers regarding your measured values
    - lambda: |-
       if (id($magnetometer).state >= 500 && !id(gas_high)) {
          id(gas_counter_total) += 0.01;
          id(gas_counter) += 1;
          id(gas_high) = true;
          ESP_LOGD("Gas", "+1");
        } else if (id($magnetometer).state <= 150 && id(gas_high)) {
          id(gas_high) = false;
        }

  - interval: 10s
    then:
    # boolean sensor for heating on/off to show when burner is on
#          ESP_LOGD("Gas", "+1");
    - lambda: |-
        // ESP_LOGI("Gas", "letzter Wert: %d", int(id(magnetometer_last_value)))
        // ESP_LOGI("Gas", "  aktuel. Wert: %d", int(id(${magnetometer}_delta).state));
       
        if (int(id(magnetometer_last_value)) == int(id(${magnetometer}_delta).state)) {
          if (id(heating_paused)) {
            id(${project_id}_heating).publish_state(false);
          }else{
            id(heating_paused) = true;
          }
        } else {
          id(heating_paused) = false;
          id(${project_id}_heating).publish_state(true);
        }
        id(magnetometer_last_value) = id(${magnetometer}_delta).state;      

binary_sensor:
# burner on/of
  - platform: template
    name: "${friendly_name} - Heizung heizt"
    id: ${project_id}_heating
    icon: 'mdi:fire'
    device_class: heat
   
sensor:
# Dallas Temperatur Sensor
# Waschhaus, Gasleitung
  - platform: dallas
    address: 0xf200000a304a6328
    id: ${project_id}_ds18b20_gas
    name: "${friendly_name} - Temperatur Gasleitung"
    device_class: temperature
    unit_of_measurement: "°C"

# Magnetometer / Gasmeter
# there are similar sensors - hmc5883l and qmc5883l
# if it looks like a hmc5883l, but dont work consider it may be a qmc5883l
  - platform: qmc5883l
    address: 0x0D
# Gasmeter X  
    field_strength_x:
      name: "${friendly_name} - Gasmeter X"
      id: ${project_id}_qmc5883lx
      accuracy_decimals: 0
      filters:
      - multiply: -1
# Gasmeter Y    
    field_strength_y:
      name: "${friendly_name} - Gasmeter Y"
      id: ${project_id}_qmc5883ly
      accuracy_decimals: 0
      filters:
      - multiply: -1
# Gasmeter Z    
    field_strength_z:
      name: "${friendly_name} - Gasmeter Z"
      id: ${project_id}_qmc5883lz
      accuracy_decimals: 0
      filters:
      - multiply: -1
    oversampling: 64x
    range: 800uT
    update_interval: 1s
   
# Gasfluss für An/Aus Erkennung
# ich habe versucht, hier einen möglichst eindeutigen Impuls zu bekommen, ohne Impulse zu verpassen, wenn er sich schnell dreht.
# Wenn der Magnet an einer ungünstigen Stelle stehen bleibt, wackelt der Wert furchtbar herum.
# ausprobieren!
  - platform: template
    name: "${friendly_name} - Gasmeter Y Delta"
    id: ${magnetometer}_delta
    lambda: |-
      return id($magnetometer).state/2;
    update_interval: 2s
    accuracy_decimals: 0
    icon: 'mdi:fire'
    device_class: gas
    state_class: measurement
    unit_of_measurement: "uT"
    filters:
    - max:
#        window_size: 3
#        send_every: 5
#        send_first_at: 3  
    - delta: 5  

# Gas Durchfluss/min
  - platform: template
    name: "${friendly_name} - Gas Durchfluss"
    id: ${project_id}_gas_momentan
    lambda: |-
      int temp = id(gas_counter);
      id(gas_counter) -= temp;
      return temp;
    update_interval: 60s
    unit_of_measurement: "Pulse"

# Gas gesamt
  - platform: template
    name: "${friendly_name} - Gas Gesamt"
    id: "${project_id}_gas_total"
    lambda: |-
      return id(gas_counter_total);
    update_interval: 600s
    unit_of_measurement: "m³"
    accuracy_decimals: 2
    icon: 'mdi:fire'
    device_class: gas
    state_class: total_increasing

# Gas kWh
  - platform: template
    name: "${friendly_name} - Gas kWh"
    id: "${project_id}_gas_kwh"
# Gasvolumen in m³ x Zustandszahl x Brennwert = Gasverbrauch in kWh
# Zustandszahl: 0.8934
# Brennwert Flüssiggas: 25,88
    filters:
    lambda: |-
      return (id(gas_counter_total) * (25.88));
    update_interval: 5s
    unit_of_measurement: "kWh"
    accuracy_decimals: 2
    icon: 'mdi:fire'
    device_class: energy
    state_class: total_increasing

# Gas  Liter
# 1 m³ = 3,93 Liter
  - platform: template
    name: "${friendly_name} - Gas Liter"
    id: "${project_id}_gas_liter"
    filters:
    lambda: |-
      return (id(gas_counter_total) * (3.93));
    update_interval: 60s
    unit_of_measurement: "L"
    accuracy_decimals: 2
    icon: 'mdi:waves'
    device_class: gas
    state_class: total_increasing
 

u5zzug

Active member
in den eingebundenen Dateien steht folgendes:

YAML:
# esphome/common/common.yaml
###################################################################
# WiFi Component - https://esphome.io/components/wifi.html
wifi:
# if no WiFi connection exists, reboot after this time.
  reboot_timeout: 30s  #default: 15min
  fast_connect: true
  ap:
    ssid: ${project_name}
    password: ${ap_password}
    channel: ${ap_channel}
    ap_timeout: ${ap_timeout}
  networks:
    - ssid: ${wifi_ssid}
      password: ${wifi_password}
  manual_ip:
    static_ip: ${static_ip}
    gateway: 192.168.1.254
    subnet: 255.255.255.0
captive_portal:
###################################################################
# Web Server Component - https://esphome.io/components/web_server.html
web_server:
  port: 80
###################################################################
# Native Home Assistant API - https://esphome.io/components/api.html
api:
  port: 6053
  password: ${api_password}
  reboot_timeout: 0s
###################################################################
# Over the Air Mode - https://esphome.io/components/ota.html
ota:
  safe_mode: true
  password: ${ota_password}
###################################################################
# Logger Component - https://esphome.io/components/logger.html
logger:
  level: $log_level


Wifi Diagnose
YAML:
# esphome/common/wifi.diag.yaml
###################################################################
# Diagnostic Wifi Sensors
sensor:
  # Wireless Signal - RSSI
  - platform: wifi_signal
    id: wifisignal
    name: ${friendly_name} - Wifi Signal
    icon: "mdi:wifi"
    update_interval: 60s
    unit_of_measurement: 'dB'
    accuracy_decimals: 0

  # Wireless Signal - Quality
  - platform: template
    id: wifi_quality
    name: ${friendly_name} - Wifi Quality
    icon: "mdi:wifi"
    update_interval: 60s
    unit_of_measurement: '%'
    accuracy_decimals: 0
    lambda: |-
      if (id(wifisignal).state < -92.0)
        return 100.0;
      if (id(wifisignal).state > -21.0)
        return 1.0;
      else
        return round(( -0.0154 * id(wifisignal).state * id(wifisignal).state )-( 0.3794 * id(wifisignal).state ) + 98.182 );

###################################################################
# Text Sensor Component - https://esphome.io/components/text_sensor/

Uptime kann man auch weglassen, wenn man es nicht braucht. Ich hatte anfangs Probleme mit dem wlan im Keller, weshalb ich den automatischen Neustart und die Uptime eingebaut habe.
YAML:
# esphome/common/uptime.diag.yaml
###################################################################
# Diagnostic Uptime Sensor
sensor:
  # Platform Uptime
  - platform: uptime
    id: ${project_id}_uptime
    name: "${friendly_name} - Uptime"
    icon: "mdi:timer"
    update_interval: 60s
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: ${project_id}_uptime_human
            state: !lambda |-
              int seconds = round(id(${project_id}_uptime).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? to_string(days) + "d " : "") +
                (hours ? to_string(hours) + "h " : "") +
                (minutes ? to_string(minutes) + "m " : "") +
                (to_string(seconds) + "s")
              ).c_str();
binary_sensor:
  - platform: status
    name: "${friendly_name} - Status"
    id: ${project_id}_status
    device_class: running
text_sensor:
  - platform: template
    name: "${friendly_name} - Uptime lesbar"
    id: ${project_id}_uptime_human
    icon: mdi:clock-start
 

u5zzug

Active member
Wenn man die ESPs vom Browser aus flashen will, braucht man https, da ich das lokal nicht habe, verwende ich https://web.esphome.io/ - geht nur in Chromium oä. oder Edge.
Unter Linux durfte ich nicht auf die nötige Schnittstelle zugreifen.
ttyUSB0 gehört dem user root und der Gruppe dialout.
Also den eigenen Nutzer zur Gruppe dialout hinzufügen und neu starten oder zumindest neu anmelden, damit die Änderung greift.
 

u5zzug

Active member
Von den 3 Magnetometer/Kompasskurven habe ich mir die ausgesucht, die mir am besten auswertbar erschien.Gas Y.pngHeizung.png
 

alexamend

Active member
Sehr schöne Arbeit, DANKE


für diejeanigen die anstelle von Flüssiggas, Erdgas haben (und hier die Werte für Normdichte und Mengengewicht das jahrüber nicht gleich sind) hier ein passendes template und zugehörige Helfer

Helfer:
Code:
{
  "version": 1,
  "minor_version": 1,
  "key": "input_number",
  "data": {
    "items": [
      {
        "id": "gas_normdichte",
        "min": 0.0,
        "max": 2.0,
        "name": "Gas Normdichte",
        "icon": "mdi:fire",
        "mode": "box",
        "step": 0.00001
      },
      {
        "id": "gas_mengengewichtet",
        "min": 0.0,
        "max": 16.0,
        "name": "Gas Mengengewichtet",
        "icon": "mdi:fire",
        "step": 0.00001,
        "mode": "box"
      }
    ]
  }
}

Helfer:______________Normdichte_____________________________Mengengewicht
Normdichte.PNG Mengengewicht.PNG

template:
YAML:
tamplate:
# Gas gesamt m³ nach kWh
  - sensor:
    - name: "Gas kWh"
      device_class: "gas"
      unit_of_measurement: "kWh"
      state: >
        {% set m3 = states('sensor.recording_gas_m3') | float %}
        {% set normdichte_value = states('input_number.gas_normdichte') | float %}
        {% set mengengewichtet_value = states('input_number.gas_mengengewichtet') | float %}
        {{ '%.4f' | format( m3*(normdichte_value * mengengewichtet_value) ) | round(4) }}
 
Zuletzt bearbeitet:

MOST2K2

New member
nö, hab doch alles hier rein geschrieben
Haste noch was geändert mittlerweile? Hab bei mir die Temperatur rausgeworfen und die Zustandszahl in die Berechnung aufgenommen, haste zwar im Kommentar geschrieben aber nicht im Code ;). Außerdem hab ich einen anderen Zähler bei mir sitzt der Magnet auf der 2-ten Nachkommastelle und damit muss ich immer 0.1 aufsummieren statt 0.01.
 

u5zzug

Active member
Bei den Sensoren muss man halt gucken, was man will und was nicht.
Die Liter und kWh Werte gucke ich kaum an,, ich schau immer nur, was gerade los ist (ob meine Regelung funktioniert) und wie der Tagesverbrauch ist.
Man könnte sicher auch den Füllstand vom Tank berechnen und Nachricht geben, wenn Gas bestellt werden sollte o.ä.

Ich müsste mal die heizt/heizt nicht Erkennung verbessern, ich hab da so stellen, wo der Sensor "zittert" und die werden falsch gemeldet. Hab mich noch nicht aufgerafft.
 

MOST2K2

New member
Was für einen Zähler hast du? Hab einen Pipersberg G4 RF1. Aktuell scheint es noch nicht zu laufen, sprich es wird noch kein Verbrauch erkannt..
 

MOST2K2

New member
Gibt es ein Problem wenn ich den initialen Wert (# initial_value: '2717.94') mitgebe? Der wert ändert sich nie..
 

u5zzug

Active member
Magnol.
Mein Magnet dreht sich in ca. 1,5min einmal. Wenn deiner weiter links ist, geht der viiiel langsamer, oder? Guck ins Log vom ESPHome. Ich hab zum Testen die Heizung aufgedreht und mit dem Tab im Keller gestanden.

Das setzt halt den Anfangswert, von wo aus gezählt wird. Ich habe den gesetzt und später auskommentiert.

Mit state_class: total_increasing zählt es zumind. nicht rückwärts.
 
Zuletzt bearbeitet:

MOST2K2

New member
Danke für deine Antwort. Ich bin genauso vorgegangen wie du und habe mit Smartphone vorm Zähler gestanden. Mein Problem ist immer noch, dass der Wert für gas_counter_total nicht hochgezählt wird. Der Screenshot zeigt, dass der Durchfluss Counter immer dann hochgezählt wird, wenn der Sensor in y-Richtung Werte über 500 anzeigt, das scheint also zu funktionieren. Woran kann das liegen?
 

Anhänge

  • Bildschirmfoto vom 2023-01-13 16-10-01.png
    Bildschirmfoto vom 2023-01-13 16-10-01.png
    41,9 KB · Aufrufe: 4

alexamend

Active member
Mit diesen Einstellungen wird er nachts zurück gesetzt, und zählt nur positives.

YAML:
homeassistant:
  customize_glob:
    sensor.stromnetz_mt681_gesamt:
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      last_reset: 1970-01-01T00:00:00+00:00
 

Zurzeit aktive Besucher

Letzte Anleitungen

Statistik des Forums

Themen
1.758
Beiträge
21.791
Mitglieder
1.254
Neuestes Mitglied
Aggro600
Oben