Die totale Überwachung ;) - SDM630M + SDM72DM + SDM120

Begonnen von rspecht, 09 August 2022, 12:56:13

Vorheriges Thema - Nächstes Thema

rspecht

Hallo Leute,

ich habe mir fürs Haus einen SDM630M, und für die Werkstatt ein SDM72DM gegönnt.
Dazu gibts fürs Büro noch ein SDM120.

Erstmal will ich euch zeigen was bisher geht, dann gehe ich auf noch offene Punkte ein.
Zuerst der Aufbau:
Von meinem Stromzähler des Versorgers gehts auf 2x Neozed Sicherungsblöcke und dann in die jeweiligen Zähler für Haus und Werkstatt und dann in die Verteilungen. Nach der Sicherung des Büros kommt noch der SDM120.
Der Modbus geht über einen Waveshare TCP-IP Koppler auf der Hutschiene. Dort wurde Modbus TCP to RTU eingestellt. https://www.waveshare.com/wiki/RS485_TO_ETH_(B)
Die Versorgung davon übernimmt das KNX Netzteil auf dem zweiten Ausgang. Dazu hab ich einfach ein 7818 mit 2 Kondensatoren & Diode in ein  kleines Gehäuse gefummelt und dazwischen geschaltet.
Die Zähler hängen in Summe mit 3m 2x0.6 TP Kabel in einem Strang an dem Koppler.
Hier die erste Frage: Brauchts bei 3m Abschlusswiderstände? Soll ich vorsichtshalber welche drauf machen?

In FHEM wurde dann das Gateway wie folgt definiert:
defmod System_Gateway_Modbus_TCP Modbus 192.168.0.xxx:4196
attr System_Gateway_Modbus_TCP room Modbus,Haus


Dann gibt es die Zähler:
defmod Haus_Strom_Meter1 ModbusSDM630M 1 180 TCP
attr Haus_Strom_Meter1 event-on-change-reading .*
attr Haus_Strom_Meter1 room Haus,Modbus

defmod Haus_Strom_Meter2 ModbusSDM72DMV2 2 180 TCP
attr Haus_Strom_Meter2 event-on-change-reading .*
attr Haus_Strom_Meter2 room Haus,Modbus

defmod Haus_Strom_Meter3 ModbusSDM120 3 180 TCP
attr Haus_Strom_Meter3 event-on-change-reading .*
attr Haus_Strom_Meter3 room Haus,Modbus

Hierzu die nächste Frage: gehe ich mit dem Intervall unter 3 Minuten fehlen Daten bei einzelnen Zählern. Kann ich dem Modul irgendwie sagen es soll die Leistungen alle Minute aber die Energie alle 5 Minuten abrufen? Damit könnte ich den Bus entlasten. Kann ich den "Rückstand" auf dem Bus messen? Das ist ja im Prinzip die Größe des Stacks.
Wenn alles "eskaliert" hab ich ab und zu mal Sprünge in der Energie im Graph - da wurde der Stack wahrscheinlich geleert. Das bedeutet aber auch ich kann den Timestamps nicht mehr trauen.

Dann gibts für die Graphen die tägliche "Nullung" des Zählers (Im folgenden für Zähler 3 da er die kleinsten Funktionen hat - alle anderen Zähler haben die Funktionen analog dazu.):
defmod atHaus_Strom_Meter3_NeuerTag at *00:00:01 {\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_export__kVArh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_export__kVArh_todayStart $temp";;;;\\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_export__kWh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_export__kWh_todayStart $temp";;;;\\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_import__kVArh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_import__kVArh_todayStart $temp";;;;\\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_import__kWh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_import__kWh_todayStart $temp";;;;\\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_total__kVArh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_total__kVArh_todayStart $temp";;;;\\
my $temp = ReadingsVal("Haus_Strom_Meter3", "Energy_total__kWh", "");;;;\\
fhem "setreading Haus_Strom_Meter3 Energy_total__kWh_todayStart $temp";;;;\\
}
attr atHaus_Strom_Meter3_NeuerTag room Haus


Hier motzt FHEM das ich temp immer wieder benutze - was kann man da tun? Ihr seht gleich in der nächsten Funktion wie ich einen Fehler umgangen hab. Mit undef temp usw. habe ich nichts erreicht.

defmod atHaus_Strom_Meter3_Calc at +*00:05:00 {\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_export__kVArh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_export__kVArh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_export__kVArh_today $temptoday";;\
}\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_export__kWh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_export__kWh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_export__kWh_today $temptoday";;\
}\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_import__kVArh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_import__kVArh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_import__kVArh_today $temptoday";;\
}\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_import__kWh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_import__kWh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_import__kWh_today $temptoday";;\
}\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_total__kVArh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_total__kVArh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_total__kVArh_today $temptoday";;\
}\
for(1){\
my $tempcurr = ReadingsNum("Haus_Strom_Meter3", "Energy_total__kWh", "");;\
my $tempstart = ReadingsNum("Haus_Strom_Meter3", "Energy_total__kWh_todayStart", "");;\
my $temptoday = $tempcurr - $tempstart;;\
fhem "setreading Haus_Strom_Meter3 Energy_total__kWh_today $temptoday";;\
}\
}
attr atHaus_Strom_Meter3_Calc alignTime 00:00
attr atHaus_Strom_Meter3_Calc room Haus


Somit bekomme ich nun plotbare Werte.
Das wird dann wie folgt dargestellt:
defmod SVG_Strom_Meter3_1 SVG DBLogging:SVG_Strom_Meter3_1:HISTORY
attr SVG_Strom_Meter3_1 plotAsPngFix 1
attr SVG_Strom_Meter3_1 plotsize 800,300
attr SVG_Strom_Meter3_1 room Haus


sowie:
# Created by FHEM/98_SVG.pm, 2022-06-13 11:00:25
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title 'Stromverbrauch - Büro'
set ytics
set y2tics
set grid
set ylabel "Energie - kWh"
set y2label "Leistung - W"

#DBLogging Haus_Strom_Meter3:Energy_import__kWh_today
#DBLogging Haus_Strom_Meter3:Power__W

plot "<IN>" using 1:2 axes x1y1 title 'Energie Heute' ls l0 lw 1 with lines,\
     "<IN>" using 1:2 axes x1y2 title 'Leistung' ls l1fill lw 1 with fsteps


Ein Bild davon ist im Anhang.
Leider gibts auch hier Fehler im LOG - wie bekomme ich es hin das nur die Zahl genutzt wird? Bei meinen Funktionen oben konnte ich ReadingsNum statt ReadingsVal nutzen. Gibts da auch einen Filter für den Plot?

2022.08.09 12:54:37 1: PERL WARNING: Argument "23 W" isn't numeric in sprintf at ./FHEM/98_SVG.pm line 2255.
2022.08.09 12:54:37 1: PERL WARNING: Argument "131 W" isn't numeric in sprintf at ./FHEM/98_SVG.pm line 2255.
2022.08.09 12:54:37 1: PERL WARNING: Argument "293 W" isn't numeric in sprintf at ./FHEM/98_SVG.pm line 2255.
2022.08.09 12:54:37 1: PERL WARNING: Argument "452.0 W" isn't numeric in sprintf at ./FHEM/98_SVG.pm line 2255.


Ach und noch etwas was ich cool finde und andere evtl. nutzen können - ein Telegram Report nachts um 12:

defmod atHaus_Strom_Report at *23:59:50 {\
my $Meter1L1 = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter1", "Energy_L1_import__kWh_today", ""));;\
my $Meter1L2 = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter1", "Energy_L2_import__kWh_today", ""));;\
my $Meter1L3 = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter1", "Energy_L3_import__kWh_today", ""));;\
my $Meter1Sum = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter1", "Energy_import__kWh_today", ""));;\
my $Meter2 = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter2", "Energy_import__kWh_today", ""));;\
my $Meter3 = sprintf("%.2f", ReadingsVal("Haus_Strom_Meter3", "Energy_import__kWh_today", ""));;\
\
fhem "set System_TelegramBot message Stromverbrauch Haus - L1: $Meter1L1 kWh, L2: $Meter1L2 kWh, L3: $Meter1L3 kWh, Summe: $Meter1Sum --- Werkstatt: $Meter2 kWh --- Büro: $Meter3 kWh";;\
fhem "set System_TelegramBot cmdSend { plotAsPng('SVG_Strom_Meter1_1') }";;\
fhem "set System_TelegramBot cmdSend { plotAsPng('SVG_Strom_Meter2_1') }";;\
fhem "set System_TelegramBot cmdSend { plotAsPng('SVG_Strom_Meter3_1') }";;\
my $Solar = sprintf("%.2f", ReadingsVal("ETA_PU15_Modbus", "Solar_Ertrag_Heute", ""));;\
my $PufferLad = sprintf("%.2f", ReadingsVal("ETA_PU15_Modbus", "Puffer_Ladung", ""));;\
my $PufferTemp = sprintf("%.2f", ReadingsVal("ETA_PU15_Modbus", "Puffer_Fuehler_1", ""));;\
fhem "set System_TelegramBot message Solarthermie Heute: $Solar kWh - Pufferladung: $PufferLad % - Puffer Oben: $PufferTemp °C";;\
fhem "set System_TelegramBot cmdSend { plotAsPng('SVG_Heizung_Solar_1') }";;\
\
}
attr atHaus_Strom_Report room Haus,System


Vielen Dank schonmal an alle die mir weiterhelfen :)
Viele Grüße

Beta-User

Umfangreich...

Immer schwierig, wenn irgendwo viele Fragen verpackt sind, ich picke mal ein paar Sachen raus:
- das mit der Variabendeklaration ist klar, einfach ab dem 2. Mal das "my" weglassen:
my $temp = ReadingsVal('Haus_Strom_Meter3', 'Energy_export__kVArh', '');;\
fhem "setreading Haus_Strom_Meter3 Energy_export__kVArh_todayStart $temp";;\
$temp = ReadingsVal('Haus_Strom_Meter3', 'Energy_export__kWh', '');;\


- Diese Tageswechsel-Geschichten erledigt mAn. "statistics" etwas eleganter
(Aber wenn man es "von Hand" macht könnte man uU. auch Schleifen nutzen, um das lesbarer zu schreiben).

- Wenn "not numeric" in/wegen Plots kommt, gibt es mehrere Varianten:
-- gleich nur den Wert in das Reading schreiben lassen (passendes readingsChange definieren, falls es das Ausgangsmodul nicht unterdrücken kann (ZWave kann das afaik nicht)?)
-- logProxy-Funktion nehmen, die das rauswirft?
-- ggf. den aus der DB gelesenen Wert bereinigen, analog zu dem, was "überall" zu on/off zu finden ist

- die Ausgabe per Push-Dienst kann man ggf. auch per msgDialog vorformatieren - das unaufgefordert jeden Tag (zu der Uhrzeit) zu bekommen wäre nicht so meins....
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Nobbynews

Zitat von: rspecht am 09 August 2022, 12:56:13
ich habe mir fürs Haus einen SDM630M, und für die Werkstatt ein SDM72DM gegönnt.
Dazu gibts fürs Büro noch ein SDM120.
Die unterschiedlichen maximalen Baudraten der einzelnen Zähler hast Du berücksichtigt?
SDM72 max. 19200 Bd (meine das das auch standardmäßig so eingestellt ist)
SDM120 max. 9600 Bd (meine das hier standardmäßig 2400 Bd eingestellt ist)
Ich betreibe hier bei mir die beiden Zähler mit 9600 bd über RS485 und einer Abfrage alle 30s.
Die teilweise größeren Intervalle ergeben sich aus der jeweiligen Definition im Modul

rspecht

Ja genau - die Baudraten haben ein "Match" bei 9600. Die Abschlusswiderstände haben wohl einiges gebracht. Ich bin bei 3 Zählern auf je 60 Sek. Intervall. Kann ich mir die "Buslast" abfragen?

rasti

Hallo,

ich habe auch einen Waveshare RS485/Modbus <=> Ethernet POE Modul,
den hier => https://www.waveshare.com/wiki/RS485_TO_POE_ETH_(B)
und mehrere Modbuszähler.
5xSDM72DM und 1x SDM230DM

Das hier habe ich verwendet als Code:
defmod System_Gateway_Modbus_TCP Modbus 192.168.178.20:502
attr System_Gateway_Modbus_TCP room Photovoltaik

defmod Haus_Strom_Meter1 ModbusSDM72DMV2 1 180 TCP
attr Haus_Strom_Meter1 event-on-change-reading .*
attr Haus_Strom_Meter1 room Photovoltaik


Konfig des Gateways ist im Screenshot.

Leider sehe ich keine Daten in FHEM.

System_Gateway_Modbus_TCP erscheint als "opened"
Haus_Strom_Meter1 erscheint als "disconnected"

Mit dem Hölldobler-Gateway => https://hoelldobler.net/Gateway/
funktioniert die Auslese, die Modbus-Verkabelung ist also OK.

Kann hier jemand helfen ?

Viele Grüße

Ralf


rasti

hier mein Code für 6 Zähler (5xsdm72 1xsdm230)

#######################
# Modbuszähler
#######################

define Haus_Strom_Meter1 ModbusSDM72DMV2 1 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter1 userattr event-on-change-reading stateFormat
attr Haus_Strom_Meter1 alias 1 - Eigene Wohnung
attr Haus_Strom_Meter1 event-on-change-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter1 room Photovoltaik
attr Haus_Strom_Meter1 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_Sum__W",0)). " / L1:" . sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0)). " / L2:" . sprintf("%.0f W", ReadingsVal($name,"Power_L2__W",0)). " / L3:" . sprintf("%.0f W", ReadingsVal($name,"Power_L3__W",0))}

define Haus_Strom_Meter2 ModbusSDM72DMV2 2 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter2 userattr event-on-change-reading stateFormat
attr Haus_Strom_Meter2 alias 2 - Wohnung 2
attr Haus_Strom_Meter2 event-on-change-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter2 room Photovoltaik
attr Haus_Strom_Meter2 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_Sum__W",0)). " / L1:" . sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0)). " / L2:" . sprintf("%.0f W", ReadingsVal($name,"Power_L2__W",0)). " / L3:" . sprintf("%.0f W", ReadingsVal($name,"Power_L3__W",0))}

define Haus_Strom_Meter3 ModbusSDM72DMV2 3 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter3 userattr event-on-change-reading stateFormat
attr Haus_Strom_Meter3 alias 3 - Wohnung 3
attr Haus_Strom_Meter3 event-on-change-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter3 room Photovoltaik
attr Haus_Strom_Meter3 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_Sum__W",0)). " / L1:" . sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0)). " / L2:" . sprintf("%.0f W", ReadingsVal($name,"Power_L2__W",0)). " / L3:" . sprintf("%.0f W", ReadingsVal($name,"Power_L3__W",0))}

define Haus_Strom_Meter4 ModbusSDM72DMV2 4 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter4 userattr event-on-update-reading stateFormat
attr Haus_Strom_Meter4 alias 4 -  Allgemeinstrom
attr Haus_Strom_Meter4 event-on-update-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter4 room Photovoltaik
attr Haus_Strom_Meter4 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_Sum__W",0)). " / L1:" . sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0)). " / L2:" . sprintf("%.0f W", ReadingsVal($name,"Power_L2__W",0)). " / L3:" . sprintf("%.0f W", ReadingsVal($name,"Power_L3__W",0))}

define Haus_Strom_Meter5 ModbusSDM72DMV2 5 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter5 userattr event-on-update-reading stateFormat
attr Haus_Strom_Meter5 alias 5 - Wärmepumpe
attr Haus_Strom_Meter5 event-on-update-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter5 room Photovoltaik
attr Haus_Strom_Meter5 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_Sum__W",0)). " / L1:" . sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0)). " / L2:" . sprintf("%.0f W", ReadingsVal($name,"Power_L2__W",0)). " / L3:" . sprintf("%.0f W", ReadingsVal($name,"Power_L3__W",0))}

define Haus_Strom_Meter6 ModbusSDM72DMV2 6 10 192.168.178.20:502 TCP
attr Haus_Strom_Meter6 userattr event-on-change-reading stateFormat
attr Haus_Strom_Meter6 alias 6 - Klima Wohnzimmer
attr Haus_Strom_Meter6 event-on-change-reading Energy_import__kWh:.1,Power_L1__W:5,Power_L2__W:5,Power_L3__W:5,Power_Sum__W:5
attr Haus_Strom_Meter6 room Photovoltaik
attr Haus_Strom_Meter6 stateFormat {sprintf("Energy: %.0f kWh", (ReadingsVal($name,"Energy_import__kWh",0) ) )." / Power:". sprintf("%.0f W", ReadingsVal($name,"Power_L1__W",0))}

jw2013

@rasti, auf diese Art macht jedes ModbusAttr Modul eine eigene TCP Verbindung auf, je nach RS486<->Netzwerk Gateway skaliert das nicht.

Ich habe es auf die andere Art hinbekommen, wie Du es zuerst versucht hast: Mit zentralem Modbus TCP Gateway Modul, und IODev bei den einzelnen Modulen, benötigt insgesamt nur eine TCP Verbindung.

Das Waveshare Gateway sollte aber als TCP Server konfiguriert sein, nicht als TCP Client?

Beste Grüße
- jens