Wie man einen Ferrariszähler mittels TRCT5000 und ESP8266 ausliest, findet man im Netz öfter. Auch @Simon42 hat hierzu bereits einen Beitrag geschrieben: https://www.simon42.com/home-assistant-ferraris-zahler-ht-nt-tarif/.
Im Zusammenhang mit einem Balkonkraftwerk (BKW) kann die Drehscheibe auch mal rückwärts drehen. Hierzu habe ich keine Lösung im Netz gefunden. Ich bin noch in der glücklichen Lage, einen Ferrariszähler zu besitzen und erspare mir damit Überlegungen zum Anschluss eines Speichers. Nun möchte ich aber auch gerne wissen, wieviel Strom ich ins Netz “speichere”.
Hier also meine Lösung.
Um Rechts- und Linkslauf bestimmen zu können, benötigt man zwei Lichtschranken (LS1 und LS2).
Hier die schematische Darstellung mit zeitlichem Ablauf:
Hier der Schaltplan und Stückliste:
Nach dem Löten und Verkabeln sieht das Ganze so aus:
Den D1 mini habe ich im Gehäuse ausserhalb des Verteilerschranks angebracht, da sonst der WLAN-Empfang zu schwach wird.
Die LEDs der beiden TRCT5000 musste ich ein wenig zueinander biegen, damit die rote Markierung der Zählscheibe zeitgleich von beiden Lichtschranken erkannt wird.
Zur Befestigung der beiden TRCT5000 an den Stromzähler habe ich ein Stück HDF-Platte 3 mm Dicke genutzt, in dem ich einen Schlitz für die Leuchtdioden mit Bohrer und Feile eingebracht habe. Die beiden Löcher rechts und links der Lichtschranken dienen der Ausrichtung am Stromzähler. Dadurch kann ich beim Ausrichten die Drehscheibe orten.
Befestigt habe ich das Ganze mit Lochband und Gummiringe .
Jetzt kommen wir zur Software:
Auf den D1 Mini habe ich über ESPHome folgende YAML geflasht:
esphome:
name: esp-stromzaehler
friendly_name: ESP-Stromzaehler
esp8266:
board: d1_mini
# Enable logging
logger:
level: DEBUG
#level: NONE
# Enable Home Assistant API
api:
encryption:
key: "xxx" # individuelles Password
ota:
- platform: esphome
password: "xxx" # individuelles Password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esp-Stromzaehler"
password: "xxx" # individuelles Password
captive_portal:
globals:
- id: Rechtslauf # true: Rechtslauf erkannt; false: Linkslauf erkannt
type: bool
restore_value: false
initial_value: 'false' # Initialwert bei Neustart (Spannung anlegen)
- id: SaveRechtslauf # Sicherung der letzten Drehrichtung für Sensor "Leistung"
# true: Rechtslauf; false: Linkslauf
type: bool
restore_value: false
initial_value: 'false' # Initialwert bei Neustart (Spannung anlegen)
- id: FreigabeUmd # Zählimpulserkennung für Ausspeisung bzw. Einsteisung, true: ist freigegeben; false: ist gesperrt
type: bool
restore_value: false
initial_value: 'false' # Initialwert bei Neustart (Spannung anlegen)
- id: FreigabeLeistung # Zählimpulserkennung für Leistungsberechnung, true: ist freigegeben; false: ist gesperrt
type: bool
restore_value: false
initial_value: 'false' # Initialwert bei Neustart (Spannung anlegen)
- id: ImpulseRechts # Anzahl der Impulse Rechtsdrehung (seit dem letzten Start)
type: int
restore_value: false
initial_value: '0' # Initialwert bei Neustart (Spannung anlegen)
- id: ImpulseLinks # Anzahl der Impulse Linksdrehung (seit dem letzten Start)
type: int
restore_value: false
initial_value: '0' # Initialwert bei Neustart (Spannung anlegen)
- id: LS # für LogAusgabe: Lichtschranke: "LS1" oder "LS2"
type: std::string
- id: aktion # für LogAusgabe: Aktion, die die Lichtschranke "LS" ausgelöst hat: "on_press" oder "on_release"
type: std::string
binary_sensor:
# Lichtschranke "LS1"
- platform: gpio
id: LS1_Impuls
name: LS1_Impuls # Impuls von Lichtschranke "LS1"
internal: true
pin:
number: D5 # Lichtschranke "LS1"
allow_other_uses: true
mode:
input: true
pullup: true
filters:
- delayed_on: 50ms
on_press: # Stromzählscheibe rot
then:
- lambda:
id(LS) = "LS1";
id(aktion) = "on_press";
- script.execute: StromzaehlscheibeRot
on_release: # Stromzählscheibe silber
then:
- lambda:
id(LS) = "LS1";
id(aktion) = "on_release";
- script.execute: StromzaehlscheibeSilber
- platform: gpio
# Lichtschranke "LS2"
id: LS2_Impuls
name: LS2_Impuls # Impuls von Lichtschranke "LS2"
internal: true
pin:
number: D2 # Lichtschranke "LS2"
mode:
input: true
pullup: true
filters:
- delayed_on: 50ms
on_press: # Stromzählscheibe rot
then:
- lambda:
id(LS) = "LS2";
id(aktion) = "on_press";
- script.execute: StromzaehlscheibeRot
on_release: # Stromzählscheibe silber
then:
- lambda:
id(LS) = "LS2";
id(aktion) = "on_release";
- script.execute: StromzaehlscheibeSilber
number:
# Stromausspeisung
- platform: template
id: Stromausspeisung
name: Stromausspeisung
icon: "mdi:meter-electric"
optimistic: true
min_value: 0
max_value: 9999999
step: 1
update_interval: 0s
# Stromeinspeisung
- platform: template
id: Stromeinspeisung
name: Stromeinspeisung
icon: "mdi:meter-electric"
optimistic: true
min_value: 0
max_value: 9999999
step: 1
update_interval: 0s
sensor:
# Leistungsermittlung mittels Puls_meter
- platform: pulse_meter
pin:
number: D5 # Lichtschranke LS1
allow_other_uses: true
name: "Leistung"
unit_of_measurement: 'W'
device_class: power
state_class: measurement
accuracy_decimals: 0
internal_filter: 100ms
internal_filter_mode: PULSE
timeout: 20min
filters:
#
# Wenn "FreigabeLeistung" false, dann wird der Impuls nicht ausgewertet.
# Wenn Drehrichtungsumkehr erkannt, dann 0 W zurückgeben.
# Wenn "LS1" true und "LS2" false und "Rechtslauf", dann Leistung berechnen,
# wenn "LS1" true und "LS2" true und "Linkslauf", dann Leistung berechnen,
# ansonsten 0 W (Drehrichtungsumkehr) zurückgeben.
#
# Impulsdauer [Impulse/min] multiplizieren mit
# 800.0 = 60 Minuten pro Stunde / 75 Impulse pro 1000 Wh
# 1.03 = für die Länge der roten Markierung 3% Zuschlag
# positiver Wert: Stromausspeisung aus dem öffentlichen Netz
# negativer Wert: Stromeinspeisung in das öffentlichen Netz
- lambda: |-
if (!id(FreigabeLeistung)) return {};
id(FreigabeLeistung) = false;
if (id(SaveRechtslauf) != id(Rechtslauf))
{id(SaveRechtslauf) = id(Rechtslauf);
return {0};
}
if (id(LS1_Impuls).state && !id(LS2_Impuls).state && id(SaveRechtslauf))
{return x * 800.0 * 1.03;
}
else if (id(LS1_Impuls).state && id(LS2_Impuls).state && !id(SaveRechtslauf))
{return x * 800.0 * -1.03;
}
else {
return {0};
}
script:
- id: StromzaehlscheibeRot # wird von beiden LSs aufgerufen, wenn "Rot" erkannt wird
then:
# wenn LS1 = high und LS2 = low dann Rechtslauf
# wenn LS1 = low und LS2 = high dann Linkslauf
# wenn beide LSs "rot" erkennen und Zählimpulserkennung ist freigegeben,
# dann wird eine Umdrehung gezählt (entweder Rechtsumdrehung oder Linksumdrehung)
# und der Nummernsensor "Stromausspeisung" bzw. "Stromeinspeisung" gesetzt
- lambda:
if (id(LS1_Impuls).state && !id(LS2_Impuls).state)
{if (id(FreigabeUmd) && !id(Rechtslauf))
{id(FreigabeUmd) = false;
}
id(Rechtslauf) = true;
};
if (!id(LS1_Impuls).state && id(LS2_Impuls).state)
{if (id(FreigabeUmd) && id(Rechtslauf))
{id(FreigabeUmd) = true;
}
id(Rechtslauf) = false;
};
if (id(LS1_Impuls).state && id(LS2_Impuls).state && id(FreigabeUmd))
{id(FreigabeUmd) = false;
if (id(Rechtslauf))
{id(ImpulseRechts) += 1;
auto call = id(Stromausspeisung).make_call();
call.set_value(float(id(ImpulseRechts)));
call.perform();
}
else {id(ImpulseLinks) += 1;
auto call = id(Stromeinspeisung).make_call();
call.set_value(float(id(ImpulseLinks)));
call.perform();
}
}
- script.execute: LogAusgabe
- id: StromzaehlscheibeSilber # wird von beiden LSs aufgerufen, wenn "Silber" erkannt wird
then:
# wenn beide LSs "silber" erkennen, dann wird Zählimpulserkennung (FreigabeUmd) und
# Leistungsmessung (FreigabeLeistung) wieder freigegeben
# wenn "LS1" der Auslöser (on_release) ist, dann Linkslauf, sonst Rechtslauf
- lambda:
if (!id(LS1_Impuls).state && !id(LS2_Impuls).state)
{id(FreigabeUmd) = true;
id(FreigabeLeistung) = true;
if (id(LS) == "LS1")
{id(Rechtslauf) = false;
}
else {id(Rechtslauf) = true;
}
}
- script.execute: LogAusgabe
- id: LogAusgabe
then:
- logger.log:
format: "Lichtschranke: %s"
args: ['id(LS).c_str()']
level: INFO
- logger.log:
format: "Aktion: %s"
args: ['id(aktion).c_str()']
level: INFO
- logger.log:
format: "LS1_Impuls %i"
args: ['id(LS1_Impuls).state']
level: INFO
- logger.log:
format: "LS2_Impuls %i"
args: ['id(LS2_Impuls).state']
level: INFO
- logger.log:
format: "Rechtslauf %i"
args: ['id(Rechtslauf)']
level: INFO
- logger.log:
format: "ImpulseRechts %i"
args: ['id(ImpulseRechts)']
level: INFO
- logger.log:
format: "ImpulseLinks %i"
args: ['id(ImpulseLinks)']
level: INFO
- logger.log:
format: "FreigabeUmd %i"
args: ['id(FreigabeUmd)']
level: INFO
- logger.log:
format: "FreigabeLeistung %i"
args: ['id(FreigabeLeistung)']
level: INFO
Der Sensor “Leistung” ermittelt mittels “pulse_meter” die aktuelle Leistung des Stromzählers in [W], positive Werte bei Strombezug, negative Werte bei Stromeinspeisung.
In HomeAssistant auf dem Raspberry Pi müssen dann noch folgende Arbeiten ausgeführt werden:
Über das UI zwei Helfer als “Counter” anlegen:
“StromAusspeisung_Impulse”
“StromEinspeisung_Impulse”
Bei dem Helfer “StromAusspeisung_Impulse” kann man als Anfangswert den Zählerstand (in Impulse) angeben, bei mir also (Zählerstand * 75 U/kWh). Dann liefert der Helfer den aktuellen Zählerstand.
Sensoren in die “configuration.yaml” hinzufügen:
template:
- sensor:
- name: "StromEinspeisung"
unique_id: 'sensor.stromeinspeisung'
device_class: 'energy'
unit_of_measurement: "kWh"
state: "{{ (states('counter.stromeinspeisung_impulse')|int / 75) | round(3) }}"
state_class: 'total_increasing'
- name: "StromAusspeisung"
unique_id: 'sensor.stromausspeisung'
device_class: 'energy'
unit_of_measurement: "kWh"
state: "{{ (states('counter.stromausspeisung_impulse')|int / 75) | round(3) }}"
state_class: 'total_increasing'
- name: "StromZaehlerStand"
unique_id: 'sensor.stromzaehlerstand'
device_class: 'energy'
unit_of_measurement: "kWh"
state: "{{ (states('sensor.stromausspeisung')|float
- states('sensor.stromeinspeisung')|float) | round(1) }}"
state_class: 'total'
Für die Automationen folgenden Code in die “automations.yaml” einfügen (oder über das UI eingeben):
- id: '123' # individuelle id
alias: StromAusspeisungErhöhen
description: Erhöht die Stromausspeisung um eine Umdrehung, also um 1/75 kWh = 0.01333
kWh.
trigger:
- platform: state
entity_id:
- number.esp_stromzaehler_stromausspeisung
condition: []
action:
- service: counter.increment
metadata: {}
data: {}
target:
entity_id: counter.stromausspeisung_impulse
mode: queued
- id: '456' # individuelle id
alias: StromEinspeisungErhöhen
description: Erhöht die Stromeinspeisung um eine Umdrehung, also um 1/75 kWh = 0.01333
kWh.
trigger:
- platform: state
entity_id:
- number.esp_stromzaehler_stromeinspeisung
condition: []
action:
- service: counter.increment
target:
entity_id:
- counter.stromeinspeisung_impulse
data: {}
mode: queued
Bei mir funktioniert die Strommessung mit dem oben beschriebenen Aufbau jetzt seit ca 2 Wochen problemlos.