Kostal Plenticore 10 Plus: Unterschied zwischen den Versionen

Aus FHEMWiki
Keine Bearbeitungszusammenfassung
Zeile 57: Zeile 57:
</pre>
</pre>
4.  Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird.
4.  Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird.
5. Verwendete Module
<pre>
- Modbus
- HttpMod
- LogDb
- LogDbRep
- dummy
- Shelly
- HourCounter
- readingsGroup
<pre>


== Einbindung in FHEM: Überblick ==
== Einbindung in FHEM: Überblick ==
Zeile 119: Zeile 131:
== Statistiken ==
== Statistiken ==
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, jedoch auch zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen.
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, jedoch auch zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen.
== 1.1 Kostal Plenticore Plus ==
== 1.1 Kostal Plenticore Plus ==


Zeile 136: Zeile 149:


- RAW Definition des Wechselrichters
- RAW Definition des Wechselrichters
 
<pre>
defmod PV_Anlage_1 ModbusAttr 71 60 192.168.178.18:1502 TCP
attr PV_Anlage_1 DbLogExclude .*
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*,Statistic_.*
attr PV_Anlage_1 alias PV_Einspeisung
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher
attr PV_Anlage_1 dev-h-defFormat %.2f
attr PV_Anlage_1 dev-h-defLen 2
attr PV_Anlage_1 dev-h-defPoll 1
attr PV_Anlage_1 dev-h-defRevRegs 1
attr PV_Anlage_1 dev-h-defUnpack f>
attr PV_Anlage_1 dev-type-STR-format %s
attr PV_Anlage_1 dev-type-STR-len 8
attr PV_Anlage_1 dev-type-STR-revRegs 0
attr PV_Anlage_1 dev-type-STR-unpack a*
attr PV_Anlage_1 event-on-change-reading statistics_.*,Statistic_.*,Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*
attr PV_Anlage_1 group PV Eigenverbrauch
attr PV_Anlage_1 icon sani_solar
attr PV_Anlage_1 obj-h100-reading Total_DC_Power
attr PV_Anlage_1 obj-h104-format %s
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager
attr PV_Anlage_1 obj-h104-revRegs 0
attr PV_Anlage_1 obj-h104-unpack N
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV
attr PV_Anlage_1 obj-h118-reading Total_home_consumption
attr PV_Anlage_1 obj-h120-reading Isolation_resistance
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number
attr PV_Anlage_1 obj-h14-type STR
attr PV_Anlage_1 obj-h144-reading Worktime
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi
attr PV_Anlage_1 obj-h152-reading Grid_frequency
attr PV_Anlage_1 obj-h154-reading Current_Phase_1
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1
attr PV_Anlage_1 obj-h160-reading Current_Phase_2
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2
attr PV_Anlage_1 obj-h166-reading Current_Phase_3
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power
attr PV_Anlage_1 obj-h190-reading Battery_charge_current
attr PV_Anlage_1 obj-h194-format %.0f
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state
attr PV_Anlage_1 obj-h208-format %.0f
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge
attr PV_Anlage_1 obj-h212-reading Battery_state
attr PV_Anlage_1 obj-h214-reading Battery_temperature
attr PV_Anlage_1 obj-h216-reading Battery_voltage
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)
attr PV_Anlage_1 obj-h258-reading Current_DC1
attr PV_Anlage_1 obj-h260-reading Power_DC1
attr PV_Anlage_1 obj-h266-reading Voltage_DC1
attr PV_Anlage_1 obj-h268-reading Current_DC2
attr PV_Anlage_1 obj-h270-reading Power_DC2
attr PV_Anlage_1 obj-h276-reading Voltage_DC2
attr PV_Anlage_1 obj-h278-reading Current_DC3
attr PV_Anlage_1 obj-h280-reading Power_DC3
attr PV_Anlage_1 obj-h286-reading Voltage_DC3
attr PV_Anlage_1 obj-h320-reading Total_yield
attr PV_Anlage_1 obj-h322-reading Daily_yield
attr PV_Anlage_1 obj-h324-reading Yearly_yield
attr PV_Anlage_1 obj-h326-reading Monthly_yield
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)
attr PV_Anlage_1 obj-h38-type STR
attr PV_Anlage_1 obj-h384-len 16
attr PV_Anlage_1 obj-h384-reading Inverter_network_name
attr PV_Anlage_1 obj-h384-type STR
attr PV_Anlage_1 obj-h420-reading IP-address
attr PV_Anlage_1 obj-h420-type STR
attr PV_Anlage_1 obj-h428-reading IP-subnetmask
attr PV_Anlage_1 obj-h428-type STR
attr PV_Anlage_1 obj-h436-reading IP-gateway
attr PV_Anlage_1 obj-h436-type STR
attr PV_Anlage_1 obj-h446-reading IP-DNS1
attr PV_Anlage_1 obj-h446-type STR
attr PV_Anlage_1 obj-h454-reading IP-DNS2
attr PV_Anlage_1 obj-h454-type STR
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)
attr PV_Anlage_1 obj-h46-type STR
attr PV_Anlage_1 obj-h514-len 1
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer
attr PV_Anlage_1 obj-h517-type STR
attr PV_Anlage_1 obj-h525-format %c
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID
attr PV_Anlage_1 obj-h525-unpack N
attr PV_Anlage_1 obj-h527-format %c
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number
attr PV_Anlage_1 obj-h529-len 4
attr PV_Anlage_1 obj-h529-reading Work_Capacity
attr PV_Anlage_1 obj-h529-unpack N
attr PV_Anlage_1 obj-h531-format %.0f
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power
attr PV_Anlage_1 obj-h531-unpack N
attr PV_Anlage_1 obj-h535-revRegs 0
attr PV_Anlage_1 obj-h535-unpack n
attr PV_Anlage_1 obj-h551-revRegs 0
attr PV_Anlage_1 obj-h559-revRegs 0
attr PV_Anlage_1 obj-h56-format %.0f
attr PV_Anlage_1 obj-h56-reading Inverter_state
attr PV_Anlage_1 obj-h56-unpack N
attr PV_Anlage_1 obj-h575-len 1
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)
attr PV_Anlage_1 obj-h577-len 2
attr PV_Anlage_1 obj-h577-reading Generation_Energy
attr PV_Anlage_1 obj-h577-unpack N
attr PV_Anlage_1 obj-h578-reading Total_energy
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power
attr PV_Anlage_1 obj-h586-format %s
attr PV_Anlage_1 obj-h586-reading Battery_Firmware
attr PV_Anlage_1 obj-h586-unpack N
attr PV_Anlage_1 obj-h588-format %s
attr PV_Anlage_1 obj-h588-len 1
attr PV_Anlage_1 obj-h588-reading Battery_Type
attr PV_Anlage_1 obj-h588-unpack N
attr PV_Anlage_1 obj-h6-reading Inverter_article_number
attr PV_Anlage_1 obj-h6-type STR
attr PV_Anlage_1 obj-h768-len 32
attr PV_Anlage_1 obj-h768-reading Productname
attr PV_Anlage_1 obj-h768-type STR
attr PV_Anlage_1 obj-h800-len 32
attr PV_Anlage_1 obj-h800-reading Power_class
attr PV_Anlage_1 obj-h800-type STR
attr PV_Anlage_1 room Strom->Photovoltaik
attr PV_Anlage_1 sortby 01
attr PV_Anlage_1 stateFormat {sprintf("\
<TABLE>\
\
<TR>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">Batterie %s</TH>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">aktuell</TH>\
  <TH ALIGN=\"RIGHT\" WIDTH=\"20\">Hausverbrauch</TH>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">Erträge</TH>\
</TR>\
\
<TR>\
  <TD ALIGN=\"MIDDLE\" WIDTH=\"20\">\
    Leistung:  %04d W<br>\
    Temp.: %02.1f °C<br>\
    Ladung total: %2d %%<br>\
    Ladung Res.: %04d Wh\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    DC total: %05d W<br>\
    <br>\
    <br>\
    PV reserve: %05d W\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    von PV: %05d W <br>\
    von Batterie: %05d W<br>\
    vom Netz: %05d W<br>\
    ins Haus: %05d W<br>\
    Netz: %05d W\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    Tag: %05d KWh <br>\
    Monat: %05d KWh<br>\
    Jahr: %05d KWh<br>\
    Total: %05d KWh\
  </TD>\
</TR>\
\
</TABLE>\
" , \
(ReadingsVal($name,"Actual_battery_charge_-minus_or_discharge_-plus_Power",0) lt 0) ? "<span style='color:#00FF00'>Laden</span>":"<span style='color:#FF0000'>Entladen</span>" ,\
\
ReadingsVal($name,"Actual_battery_charge_-minus_or_discharge_-plus_Power",0),\
ReadingsVal($name,"Battery_temperature",0) ,\
ReadingsVal($name,"Act_state_of_charge",0) ,\
ReadingsVal($name,"Actual_battery_charge_usable_Power",0) ,\
\
ReadingsVal($name,"Power_DC_Sum","0"),\
ReadingsVal($name,"Total_PV_Power_reserve","0"),\
\
ReadingsVal($name,"Home_own_consumption_from_PV",0) ,\
ReadingsVal($name,"Home_own_consumption_from_battery",0) ,\
ReadingsVal($name,"Home_own_consumption_from_grid",0),\
ReadingsVal($name,"Home_own_consumption_from_PV",0) +ReadingsVal($name,"Home_own_consumption_from_battery",0)+ReadingsVal($name,"Home_own_consumption_from_grid",0),\
ReadingsVal($name,"Total_active_power_(powermeter)",0),\
\
round(ReadingsVal($name,"Daily_yield",0)/1000 ,0),\
round(ReadingsVal($name,"Monthly_yield",0)/1000 ,0) ,\
round(ReadingsVal($name,"Yearly_yield",0)/1000 ,0) ,\
round(ReadingsVal($name,"Total_yield",0)/1000 ,0)\
)}
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,"Power_DC1","0")+ReadingsVal($NAME,"Power_DC2","0") },\
\
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,"Power_DC_Sum","0") * 0.90 - ReadingsVal($NAME,"Home_own_consumption_from_PV","0");;;; ($reserve lt 0)?0:round($reserve,3)  },\
\
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,"Actual_battery_charge_-minus_or_discharge_-plus_current","0")*ReadingsVal($NAME,"Battery_voltage","0"));;;; ($Bat_out gt 0)?ReadingsVal($NAME,"Power_DC_Sum","0") + $Bat_out :ReadingsVal($NAME,"Power_DC_Sum","0") },\
\
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,"Actual_battery_charge_-minus_or_discharge_-plus_current","0")*ReadingsVal($NAME,"Battery_voltage","0")),0)},\
\
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (8960*(ReadingsVal($NAME,"Act_state_of_charge","0")-10)/100);;;; ($x lt 0)?0:round($x,0) },\
\
Solar_SolarRadiation:Total_DC_Power.* { my $x1 = POSIX::strftime("%Y-%m-%d_%H_00_Rad1wh",localtime(time-60*60)) ;;;; my $x2 = POSIX::strftime("%Y-%m-%d_%H_00_Rad1wh",localtime()) ;;;; my $x_avg = round((ReadingsVal("DWD_Prognose",$x1,0)+ReadingsVal("DWD_Prognose",$x2,0))/2 , 0) ;;;; my $time = POSIX::strftime("%M",localtime()) ;;;; ($time < 30)?ReadingsVal("DWD_Prognose",$x1,0):$x_avg },\
\
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,"statistics_output",0);;;; $x =~ s/"moduleid": "scb:statistic:EnergyFlow", |, "moduleid": "scb:statistic:EnergyFlow"|"processdata": \[//g;;;; $x =~ s/id": "|, "unit": "", "value"|^\[|\]\}\]$//g;;;; $x =~ s/moduleid/statistics_00_moduleid/g;;;; $x =~ s/processdata/statistics/g;;;; $x =~ s/\}\, \{/\, /g;;;; $x =~ s/\{\{/\{/g;;;; return $x }
attr PV_Anlage_1 verbose 0
<pre>


'''Userreadings'''
'''Userreadings'''
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.


Zeile 571: Zeile 817:


== 2. PV Eigenverbrauch-Steuerung ==
== 2. PV Eigenverbrauch-Steuerung ==
'''Beispiel Luft Wärme Pumpe'''
'''Beispiel Luft Wärme Pumpe'''
 
- RAW Definition LWP_LuftWärmePumpe (dummy Modul)
- RAW Definition LWP_LuftWärmePumpe
<pre>
<pre>
 
defmod LWP dummy
attr LWP DbLogExclude .*
attr LWP DbLogInclude state
attr LWP alias LWP_LuftWärmePumpe
attr LWP group PV Eigenverbrauch
attr LWP icon sani_earth_source_heat_pump
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd
attr LWP room Strom->Photovoltaik
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time
attr LWP sortby 05
attr LWP stateFormat state
attr LWP verbose 0
attr LWP webCmd LWP_Button
</pre>
</pre>
- RAW Definition LWP_PV
- RAW Definition LWP_PV (DOIF Modul)
<pre>
<pre>
defmod LWP_PV DOIF ################################################################################################################\
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\
##\
    ([LWP_Counter:pulseTimePerDay] >= [LWP:RunTimePerDay] and\
    [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
    [LWP:state] ne "off" and [LWP:LWP_Button] eq "off" )\
\
    ({Log 3, " LWP_PV cmd_1 PV : LWP off"}\
    {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
    {fhem("set LWP off")}\
    {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\
##\
DOELSEIF\
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) < [LWP:PowerLimitOff] and\
    [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
    [LWP:state] ne "off" and\
    [LWP:LWP_Button] ne "on" )\
\
    ({Log 3, " LWP_PV cmd_2 PV : LWP off"}\
    {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
    {fhem("set LWP off")}\
    {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\
##  wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\
##\
DOELSEIF\
    ([PV_Anlage_1:Total_PV_Power_reserve] < [LWP:PowerLimitOff] and\
    [LWP_PV:wait_timer] ne "no timer" and\
    [LWP_PV:wait_timer] ne "" and\
    [LWP:state] eq "off" )\
\
    ({Log 3, "LWP_PV cmd_3 PV : Stop wait timer LWP"})\
################################################################################################################\
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\
##\
DOELSEIF\
    ([Astro:ObsSeason] ne "Sommer" and [Astro:ObsSeason] ne "Frühling" and\
    [PV_Anlage_1:Total_PV_Power_reserve] >= [LWP:PowerLimitOn] and\
    [[LWP:TimeStart]-[LWP:TimeEnd]] and\
    [LWP:state] eq "off" and\
    [LWP_Counter:pulseTimePerDay] < [LWP:RunTimePerDay] and\
    [Heizung:hotWaterTemperature] < 60 )\
\
    ({Log 3, "LWP_PV cmd_4 : LWP on"}\
    {fhem("".ReadingsVal("LWP","SetCmdOn",0))}\
    {fhem("set LWP on")}\
    {fhem("set Heizung hotWaterTemperatureTarget 60.0")}\
    )\
################################################################################################################\
## 5 Signal für den PV-Modus der LWP einschalten.\
##\
DOELSEIF\
    ([LWP:LWP_Button] eq "on" )\
\
    ({Log 3, "LWP_PV cmd_5 PV : LWP on for manuel PV-Modus"}\
    {fhem("".ReadingsVal("LWP","SetCmdOn",0))}\
    {fhem("set LWP on")}\
    {fhem("set Heizung hotWaterTemperatureTarget 60.0")}\
    )\
################################################################################################################\
## 6 Signal für den PV-Modus der LWP abschalten.\
##\
DOELSEIF\
    ([LWP:LWP_Button] eq "off" and\
    [$SELF:cmd_nr] eq "5"  )\
\
    ({Log 3, "LWP_PV cmd_6 PV : LWP off after manuel PV-Modus"}\
    {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
    {fhem("set LWP off")}\
    {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\
##\
DOELSEIF\
  ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] > 300 and\
    [Heizung:opStateHeatPump1] eq "Wärmepumpe kommt" and\
    [Heizung:opStateHeatPump3] eq "Pumpenvorlauf" )\
\
    ({Log 3, "LWP_PV cmd_7 : Stop wait timer LWP"})\
################################################################################################################\
## 8 LWP Ende\
##\
DOELSEIF\
  ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] < 300 and\
    [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
    ([Heizung:opStateHeatPump1] ne "Wärmepumpe läuft" or [Heizung:opStateHeatPump3] eq "Luftabtauen" ) and\
    ([$SELF:cmd_nr] eq "4" or [$SELF:cmd_nr] eq "5" or [$SELF:cmd_nr] eq "10") )\
\
    ({Log 3, "LWP_PV cmd_8 : LWP run finished"}\
    {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
    {fhem("set LWP off")}\
    {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    {fhem("setreading LWP LWP_Button off")}\
    )\
################################################################################################################\
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\
##  Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\
##\
DOELSEIF\
  ([Astro:ObsSeason] ne "Sommer" and [Astro:ObsSeason] ne "Frühling" and\
    [[LWP:TimeEnd]] and\
    [Heizung:hotWaterTemperature] < 47 and\
    ([LWP_Counter:pulseTimePerDay] < [Pool:RunTimePerDay] or\
    [LWP_Counter:countsPerDay] eq 0) )\
\
    ({Log 3, "LWP_PV cmd_9 : LWP on for water heating"}\
\
    {fhem("set Heizung hotWaterTemperatureTarget ". (ReadingsVal("Heizung","hotWaterTemperature",46)+4))}\
\
    {Log 3, "LWP_PV cmd_9 : LWP hotWaterTemperatureTarget ".ReadingsVal("Heizung","hotWaterTemperatureTarget",0)}\
    )\
################################################################################################################\
## 10 Hohe Priorität im Winter fuer die LWP\
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\
##\
DOELSEIF\
    ([Astro:ObsSeason] eq "Winter" and\
    [PV_Anlage_1:Total_PV_Power_reserve] >= 2000 and\
    [shelly02:power_0] > 800 and\
    [PV_Anlage_1:Act_state_of_charge] > 60 and\
    [Heizung:hotWaterTemperature] < 60 and \
    [$SELF:cmd_nr] ne "10" )\
\
    ({Log 3, "LWP_PV cmd_10 : LWP Priorität"}\
    {fhem("set LWP_PV cmd_4")}\
    )\


attr LWP_PV DbLogExclude .*
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer
attr LWP_PV alias LWP_PV
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität
attr LWP_PV do always
attr LWP_PV group PV Eigenverbrauch-Steuerung
attr LWP_PV icon sani_earth_source_heat_pump
attr LWP_PV room Strom->Photovoltaik
attr LWP_PV sortby 01
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C
attr LWP_PV userReadings LWP_Status { ReadingsVal("Heizung","state","") }
attr LWP_PV verbose 5
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0
</pre>
</pre>
- RAW Definition LWP_Signale
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)
<pre>
<pre>
 
defmod shelly01 Shelly 192.168.178.55
attr shelly01 DbLogExclude .*
attr shelly01 DbLogInclude relay.*,power.*,energy.*
attr shelly01 alias LWP_Signale
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network
attr shelly01 group PV Eigenverbrauch-Steuerung
attr shelly01 icon taster_ch_1
attr shelly01 mode relay
attr shelly01 model shelly1pm
attr shelly01 room Shelly,Heizung->System,Strom->Photovoltaik
attr shelly01 sortby 02
attr shelly01 stateFormat {sprintf("\
<TABLE>\
\
<TR>\
  <TD VALIGN=\"TOP\" ALIGN=\"LEFT\" WIDTH=\"50\">\
    WebLink: %s\
  </TD>\
\
  <TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"100\">\
    Gesamt 0: %08.2f KWh<br>\
  </TD>\
\
  <TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"70\">\
    Relais 0: %s %06.1f Watt<br>\
  </TD>\
</TR>\
\
</TABLE>\
" ,\
ReadingsVal($name,"WebLink","none") ,\
ReadingsVal($name,"energy_0",0)/1000,\
(ReadingsVal($name,"relay","") eq "off") ? "<span style='color:#FF0000'>off</span>":"<span style='color:#00FF00'>on</span>",\
ReadingsVal($name,"power",0),\
)}
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,"network","");; $ip =~ s/connected to //gs;; $ip =~ s/<[^>]*>//gs;; return("<html><a href='http://".$ip."/'>WEB</a></html>") }
attr shelly01 webCmd |
</pre>
</pre>
- RAW Definition LWP_Counter
- RAW Definition LWP_Counter (HourCounter Modul)
<pre>
<pre>


</pre>
</pre>
- RAW Definition rg_LWP_Status
- RAW Definition rg_LWP_Status (readingsGroup Modul)
<pre>
<pre>


Zeile 595: Zeile 1.034:


'''Beispiel Pool'''
'''Beispiel Pool'''
 
- RAW Definition Pool_Softube (dummy Modul)
- RAW Definition Pool_Softube
<pre>
<pre>


</pre>
</pre>
- RAW Definition Pool_PV
- RAW Definition Pool_PV (DOIF Modul)
<pre>
<pre>


</pre>
</pre>
- RAW Definition Pool_Signale
- RAW Definition Pool_Signale (Shelly Modul: shelly1pm)
<pre>
<pre>


</pre>
</pre>
- RAW Definition Pool_Counter
- RAW Definition Pool_Counter (HourCounter Modul)
<pre>
<pre>


</pre>
</pre>
- RAW Definition rg_Pool_Status
- RAW Definition rg_Pool_Status (readingsGroup Modul)
<pre>
<pre>


Zeile 618: Zeile 1.056:


'''Beispiel Waschmaschine (mit Walzenschalter ;-) )'''
'''Beispiel Waschmaschine (mit Walzenschalter ;-) )'''
 
- RAW Definition Waschmaschine (dummy Modul)
- RAW Definition Waschmaschine<pre>
<pre>


</pre>
</pre>
- RAW Definition Waschmaschine_PV
- RAW Definition Waschmaschine_PV (DOIF Modul)
<pre>
<pre>


</pre>
</pre>
- RAW Definition Waschmaschine_Signale
- RAW Definition Waschmaschine_Signale (Shelly Modul: shelly2.5)
<pre>
<pre>


</pre>
</pre>
- RAW Definition Waschmaschine_Counter
- RAW Definition Waschmaschine_Counter (HourCounter Modul)
<pre>
<pre>


</pre>
</pre>
- RAW Definition rg_Waschmaschine_Status
- RAW Definition rg_Waschmaschine_Status (readingsGroup Modul)
<pre>
<pre>


Zeile 647: Zeile 1.085:


</pre>
</pre>
'''Erstellen von zusätzlichen Werten in der Datenbank'''
'''Erstellen von zusätzlichen Werten in der Datenbank'''
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft.
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft.


Zeile 669: Zeile 1.107:


'''Löschen von nicht mehr benötigten Werten in der Datenbank'''
'''Löschen von nicht mehr benötigten Werten in der Datenbank'''
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.

Version vom 28. August 2020, 13:29 Uhr

{{Infobox Hardware |Bild=|200px |Bildbeschreibung=Kostal Plenticore Plus mit BYD und KSEM |HWProtocol=IP |HWType=Hybrid Wechselrichter |HWCategory=Wechselrichter |HWVoltage=400 V |HWPoweredBy=3P AC |HWSize=39x67x45 cm (BxHxT) |HWComm=n/a |HWChannels=n/a |HWPowerConsumption=? |HWDeviceFHEM=[[HTTPMOD],[Modbus]] |HWManufacturer=Kostal GmbH }}

Achtung, diese Wiki Seite ist noch eine totale Baustelle :-) Momentan werden die Informationen noch aus den Threads im Forum hierher übertragen.


Der Kostal Plenticore 10 Plus [1] ist eine Hybrid Wechselrichter mit IP-Konnektivität.

Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!

Voraussetzungen Energietechnik

Der Wechselrichter, der Speicher und der KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim Netzbetreiber angemeldet.

Geräte-Registrierung

Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.

Einbindung in das Netzwerk

Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.

Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.

Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch deer Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.

Voraussetzungen FHEM Umfeld

1. Alle Geräte müssen mit TCP/IP erreichbar sein

2. Alle Module sollten auf einem aktuellen stand sein

3. Python

3.1 Ein Python 3 sollte vorhanden sein, wenn man die erweiterten Funktionalitäten, wie Statistiken, Speicher auslesen und später auch das Setzen von Werten im Plenticore, verwenden möchte.

3.2 Es müssen folgende Python Module vorhanden sein

pip3 install pycryptodome
pip3 install -U fhem

4. Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird.

5. Verwendete Module

- Modbus
- HttpMod
- LogDb
- LogDbRep
- dummy
- Shelly
- HourCounter
- readingsGroup
<pre>

== Einbindung in FHEM: Überblick ==

1.    Hardware Anbindung (alles über LAN)

1.1   Kostal Plenticore Plus

1.1.1 Kostal Plenticore Plus die Basis information (Modbus/TCP)
        - RAW Definition des Device
        - userreadings

1.1.2 Kostal Plenticore Plus die Statistiken (über Python Skript)
        - RAW Definition des Device
        - userreadings

1.2   Kostel Smart Energy Manager (KSEM) (Modbus/TCP)
        - RAW Definition des Device
        - userreadings

1.3   BYD Speicher (über Python Skript)

2.    PV Eigenverbrauch-Steuerung
        - RAW Definition
           LWP_LuftWärmePumpe
           LWP_PV
           LWP_Signale
           LWP_Counter
           rg_LWP_Status
        - RAW Definition
           Pool_Softube
           Pool_PV
           Pool_Signale
           Pool_Counter
           rg_Pool_Status
        - RAW Definition
           Waschmaschine
           Waschmaschine_PV
           Waschmaschine_Signale
           Waschmaschine_Counter
           rg_Waschmaschine_Status

3.    Energie Bilanz
        - RAW Definition
           Energiebilanz
           LogDBRep_PV_total_diff_Week
           LogDBRep_PV_total_max_Month
           LogDBRep_PV_used_diff_Week
           LogDBRep_PV_used_max_Month

4.    Wetter Prognose


5.    Diagramme
        - RAW Definition
           Leistungsuebersicht    - SVG_LogDB_Photovoltaik_1
           Hauptverbraucher       - SVG_LogDB_Photovoltaik_2
           Leistungsbezug         - SVG_LogDB_Photovoltaik_3
           PV_Bilanz              - SVG_LogDB_PV_Bilanz
           Forecast / Calculation - SVG_LogDB_Photovoltaik_4

== Statistiken ==
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, jedoch auch zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen.

== 1.1 Kostal Plenticore Plus ==

== 1.1.1 Einbindung in FHEM: Kostal Plenticore Plus die Basis information (Modbus/TCP) ==

Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist. 

GeräteId  : 71

IP-Adresse: <IP-Adresse>

Port      : 1502

Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk.

Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. 

- RAW Definition des Wechselrichters
<pre>
defmod PV_Anlage_1 ModbusAttr 71 60 192.168.178.18:1502 TCP
attr PV_Anlage_1 DbLogExclude .*
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*,Statistic_.*
attr PV_Anlage_1 alias PV_Einspeisung
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher
attr PV_Anlage_1 dev-h-defFormat %.2f
attr PV_Anlage_1 dev-h-defLen 2
attr PV_Anlage_1 dev-h-defPoll 1
attr PV_Anlage_1 dev-h-defRevRegs 1
attr PV_Anlage_1 dev-h-defUnpack f>
attr PV_Anlage_1 dev-type-STR-format %s
attr PV_Anlage_1 dev-type-STR-len 8
attr PV_Anlage_1 dev-type-STR-revRegs 0
attr PV_Anlage_1 dev-type-STR-unpack a*
attr PV_Anlage_1 event-on-change-reading statistics_.*,Statistic_.*,Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*
attr PV_Anlage_1 group PV Eigenverbrauch
attr PV_Anlage_1 icon sani_solar
attr PV_Anlage_1 obj-h100-reading Total_DC_Power
attr PV_Anlage_1 obj-h104-format %s
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager
attr PV_Anlage_1 obj-h104-revRegs 0
attr PV_Anlage_1 obj-h104-unpack N
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV
attr PV_Anlage_1 obj-h118-reading Total_home_consumption
attr PV_Anlage_1 obj-h120-reading Isolation_resistance
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number
attr PV_Anlage_1 obj-h14-type STR
attr PV_Anlage_1 obj-h144-reading Worktime
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi
attr PV_Anlage_1 obj-h152-reading Grid_frequency
attr PV_Anlage_1 obj-h154-reading Current_Phase_1
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1
attr PV_Anlage_1 obj-h160-reading Current_Phase_2
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2
attr PV_Anlage_1 obj-h166-reading Current_Phase_3
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power
attr PV_Anlage_1 obj-h190-reading Battery_charge_current
attr PV_Anlage_1 obj-h194-format %.0f
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state
attr PV_Anlage_1 obj-h208-format %.0f
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge
attr PV_Anlage_1 obj-h212-reading Battery_state
attr PV_Anlage_1 obj-h214-reading Battery_temperature
attr PV_Anlage_1 obj-h216-reading Battery_voltage
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)
attr PV_Anlage_1 obj-h258-reading Current_DC1
attr PV_Anlage_1 obj-h260-reading Power_DC1
attr PV_Anlage_1 obj-h266-reading Voltage_DC1
attr PV_Anlage_1 obj-h268-reading Current_DC2
attr PV_Anlage_1 obj-h270-reading Power_DC2
attr PV_Anlage_1 obj-h276-reading Voltage_DC2
attr PV_Anlage_1 obj-h278-reading Current_DC3
attr PV_Anlage_1 obj-h280-reading Power_DC3
attr PV_Anlage_1 obj-h286-reading Voltage_DC3
attr PV_Anlage_1 obj-h320-reading Total_yield
attr PV_Anlage_1 obj-h322-reading Daily_yield
attr PV_Anlage_1 obj-h324-reading Yearly_yield
attr PV_Anlage_1 obj-h326-reading Monthly_yield
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)
attr PV_Anlage_1 obj-h38-type STR
attr PV_Anlage_1 obj-h384-len 16
attr PV_Anlage_1 obj-h384-reading Inverter_network_name
attr PV_Anlage_1 obj-h384-type STR
attr PV_Anlage_1 obj-h420-reading IP-address
attr PV_Anlage_1 obj-h420-type STR
attr PV_Anlage_1 obj-h428-reading IP-subnetmask
attr PV_Anlage_1 obj-h428-type STR
attr PV_Anlage_1 obj-h436-reading IP-gateway
attr PV_Anlage_1 obj-h436-type STR
attr PV_Anlage_1 obj-h446-reading IP-DNS1
attr PV_Anlage_1 obj-h446-type STR
attr PV_Anlage_1 obj-h454-reading IP-DNS2
attr PV_Anlage_1 obj-h454-type STR
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)
attr PV_Anlage_1 obj-h46-type STR
attr PV_Anlage_1 obj-h514-len 1
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer
attr PV_Anlage_1 obj-h517-type STR
attr PV_Anlage_1 obj-h525-format %c
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID
attr PV_Anlage_1 obj-h525-unpack N
attr PV_Anlage_1 obj-h527-format %c
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number
attr PV_Anlage_1 obj-h529-len 4
attr PV_Anlage_1 obj-h529-reading Work_Capacity
attr PV_Anlage_1 obj-h529-unpack N
attr PV_Anlage_1 obj-h531-format %.0f
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power
attr PV_Anlage_1 obj-h531-unpack N
attr PV_Anlage_1 obj-h535-revRegs 0
attr PV_Anlage_1 obj-h535-unpack n
attr PV_Anlage_1 obj-h551-revRegs 0
attr PV_Anlage_1 obj-h559-revRegs 0
attr PV_Anlage_1 obj-h56-format %.0f
attr PV_Anlage_1 obj-h56-reading Inverter_state
attr PV_Anlage_1 obj-h56-unpack N
attr PV_Anlage_1 obj-h575-len 1
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)
attr PV_Anlage_1 obj-h577-len 2
attr PV_Anlage_1 obj-h577-reading Generation_Energy
attr PV_Anlage_1 obj-h577-unpack N
attr PV_Anlage_1 obj-h578-reading Total_energy
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power
attr PV_Anlage_1 obj-h586-format %s
attr PV_Anlage_1 obj-h586-reading Battery_Firmware
attr PV_Anlage_1 obj-h586-unpack N
attr PV_Anlage_1 obj-h588-format %s
attr PV_Anlage_1 obj-h588-len 1
attr PV_Anlage_1 obj-h588-reading Battery_Type
attr PV_Anlage_1 obj-h588-unpack N
attr PV_Anlage_1 obj-h6-reading Inverter_article_number
attr PV_Anlage_1 obj-h6-type STR
attr PV_Anlage_1 obj-h768-len 32
attr PV_Anlage_1 obj-h768-reading Productname
attr PV_Anlage_1 obj-h768-type STR
attr PV_Anlage_1 obj-h800-len 32
attr PV_Anlage_1 obj-h800-reading Power_class
attr PV_Anlage_1 obj-h800-type STR
attr PV_Anlage_1 room Strom->Photovoltaik
attr PV_Anlage_1 sortby 01
attr PV_Anlage_1 stateFormat {sprintf("\
<TABLE>\
\
<TR>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">Batterie %s</TH>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">aktuell</TH>\
  <TH ALIGN=\"RIGHT\" WIDTH=\"20\">Hausverbrauch</TH>\
  <TH ALIGN=\"MIDDLE\" WIDTH=\"20\">Erträge</TH>\
</TR>\
\
<TR>\
  <TD ALIGN=\"MIDDLE\" WIDTH=\"20\">\
    Leistung:  %04d W<br>\
    Temp.: %02.1f °C<br>\
    Ladung total: %2d %%<br>\
    Ladung Res.: %04d Wh\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    DC total: %05d W<br>\
    <br>\
    <br>\
    PV reserve: %05d W\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    von PV: %05d W <br>\
    von Batterie: %05d W<br>\
    vom Netz: %05d W<br>\
    ins Haus: %05d W<br>\
    Netz: %05d W\
  </TD>\
\
  <TD ALIGN=\"RIGHT\" WIDTH=\"20\">\
    Tag: %05d KWh <br>\
    Monat: %05d KWh<br>\
    Jahr: %05d KWh<br>\
    Total: %05d KWh\
  </TD>\
</TR>\
\
</TABLE>\
" , \
(ReadingsVal($name,"Actual_battery_charge_-minus_or_discharge_-plus_Power",0) lt 0) ? "<span style='color:#00FF00'>Laden</span>":"<span style='color:#FF0000'>Entladen</span>" ,\
\
ReadingsVal($name,"Actual_battery_charge_-minus_or_discharge_-plus_Power",0),\
ReadingsVal($name,"Battery_temperature",0) ,\
ReadingsVal($name,"Act_state_of_charge",0) ,\
ReadingsVal($name,"Actual_battery_charge_usable_Power",0) ,\
\
ReadingsVal($name,"Power_DC_Sum","0"),\
ReadingsVal($name,"Total_PV_Power_reserve","0"),\
\
ReadingsVal($name,"Home_own_consumption_from_PV",0) ,\
ReadingsVal($name,"Home_own_consumption_from_battery",0) ,\
ReadingsVal($name,"Home_own_consumption_from_grid",0),\
ReadingsVal($name,"Home_own_consumption_from_PV",0) +ReadingsVal($name,"Home_own_consumption_from_battery",0)+ReadingsVal($name,"Home_own_consumption_from_grid",0),\
ReadingsVal($name,"Total_active_power_(powermeter)",0),\
\
round(ReadingsVal($name,"Daily_yield",0)/1000 ,0),\
round(ReadingsVal($name,"Monthly_yield",0)/1000 ,0) ,\
round(ReadingsVal($name,"Yearly_yield",0)/1000 ,0) ,\
round(ReadingsVal($name,"Total_yield",0)/1000 ,0)\
)}
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,"Power_DC1","0")+ReadingsVal($NAME,"Power_DC2","0") },\
\
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,"Power_DC_Sum","0") * 0.90 - ReadingsVal($NAME,"Home_own_consumption_from_PV","0");;;; ($reserve lt 0)?0:round($reserve,3)  },\
\
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,"Actual_battery_charge_-minus_or_discharge_-plus_current","0")*ReadingsVal($NAME,"Battery_voltage","0"));;;; ($Bat_out gt 0)?ReadingsVal($NAME,"Power_DC_Sum","0") + $Bat_out :ReadingsVal($NAME,"Power_DC_Sum","0") },\
\
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,"Actual_battery_charge_-minus_or_discharge_-plus_current","0")*ReadingsVal($NAME,"Battery_voltage","0")),0)},\
\
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (8960*(ReadingsVal($NAME,"Act_state_of_charge","0")-10)/100);;;; ($x lt 0)?0:round($x,0) },\
\
Solar_SolarRadiation:Total_DC_Power.* { my $x1 = POSIX::strftime("%Y-%m-%d_%H_00_Rad1wh",localtime(time-60*60)) ;;;; my $x2 = POSIX::strftime("%Y-%m-%d_%H_00_Rad1wh",localtime()) ;;;; my $x_avg = round((ReadingsVal("DWD_Prognose",$x1,0)+ReadingsVal("DWD_Prognose",$x2,0))/2 , 0) ;;;; my $time = POSIX::strftime("%M",localtime()) ;;;; ($time < 30)?ReadingsVal("DWD_Prognose",$x1,0):$x_avg },\
\
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,"statistics_output",0);;;; $x =~ s/"moduleid": "scb:statistic:EnergyFlow", |, "moduleid": "scb:statistic:EnergyFlow"|"processdata": \[//g;;;; $x =~ s/id": "|, "unit": "", "value"|^\[|\]\}\]$//g;;;; $x =~ s/moduleid/statistics_00_moduleid/g;;;; $x =~ s/processdata/statistics/g;;;; $x =~ s/\}\, \{/\, /g;;;; $x =~ s/\{\{/\{/g;;;; return $x }
attr PV_Anlage_1 verbose 0
<pre>

'''Userreadings'''
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.

Power_DC_Sum
   Trigger: Total_DC_Power.*
   Dies berechnet direkt die Summe der DC-Leistung. Wenn der Plenticore einen Speicher hat, wird dieser am String 3 angeschlossen,
   sollte also kein Speicher vorhanden sein muss man hier den dritten String auch noch addieren.
Total_PV_Power_reserve
   Trigger: Total_DC_Power.*
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.
Total_DC_Power_Max
   Trigger: Total_DC_Power.*
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.
Actual_battery_charge_-minus_or_discharge_-plus_Power
   Trigger: Actual_battery_charge_-minus_or_discharge_-plus_current.*
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.
Actual_battery_charge_usable_Power
   Trigger: Act_state_of_charge.*
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im "Battery_Type 892941625" stecken könnte. 8929 >> 8.93 KW ???
Solar_SolarRadiation
   Trigger: Total_DC_Power.*
   Wer noch keine Wetter prognose verwendet kann dieses reading entfernen. Das wird später noch behandelt.
statistics_clean
   Trigger: statistics_output.*
   Dies ist ein temporäres reading, das nur als zwischen Schritt für die Erstellung der Statistics_* readings verwendet wird. Befüllt wird zuerst
   das reading statistics_output durch ein regelmäßig laufendes Python Skript. Auch dies wird noch später behandelt.
   Wer keine Statistiken haben möchte kann das einfach entfernen.

== 1.1.2 Einbindung in FHEM: Kostal Plenticore Plus die Statistiken (über Python Skript) ==

Die Statistiken des Plenticore sind noch eine Zusatzinformation, die nicht über Modbus/TCP übermittelt wird. Diese lassen sich nur über die API des Plenticore abfragen.
<pre>
http://<IP-Address_Plenticore/api/v1

Dateiverzeichnis:

/opt/fhem
/opt/fhem/python/pwd_fhem.json
/opt/fhem/python/pwd_plenticore.json
/opt/fhem/python/bin
/opt/fhem/python/bin/plenticore_statistic.py

Python:

fhem@raspberrypi:~/python/bin$ which python3
/usr/bin/python3
fhem@raspberrypi:~/python/bin$ python3 --version
Python 3.7.3

fhem@raspberrypi:~/python/bin$ cat plenticore_statistic.py

import random
import string
import base64
import json
import requests
import hashlib
import os
import hmac
from Crypto.Cipher import AES
import binascii

import fhem
import asyncio

import sys
plenticore = sys.argv[1]
web        = sys.argv[2]
request    = '/processdata/scb:statistic:EnergyFlow' 

try:
    with open('/opt/fhem/python/pwd_plenticore.json', 'r') as f:
        credentials=json.load(f)
except Exception as e:
    print('Something went wrong: {}'.format(e))

USER_TYPE = credentials["username"]
PASSWD = credentials["password"]
BASE_URL = "http://" + plenticore + "/api/v1"
AUTH_START = "/auth/start"
AUTH_FINISH = "/auth/finish"
AUTH_CREATE_SESSION = "/auth/create_session"
ME = "/auth/me"

def randomString(stringLength):
    letters = string.ascii_letters
    return ''.join(random.choice(letters) for i in range(stringLength))''

u = randomString(12)
u = base64.b64encode(u.encode('utf-8')).decode('utf-8')

step1 = {
  "username": USER_TYPE,
  "nonce": u
}
step1 = json.dumps(step1)

url = BASE_URL + AUTH_START
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step1, headers=headers)
response = json.loads(response.text)
i = response['nonce']
e = response['transactionId']
o = response['rounds']
a = response['salt']
bitSalt = base64.b64decode(a)

def getPBKDF2Hash(password, bytedSalt, rounds):
    return hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), bytedSalt, rounds)

r = getPBKDF2Hash(PASSWD,bitSalt,o)
s = hmac.new(r, "Client Key".encode('utf-8'), hashlib.sha256).digest()
c = hmac.new(r, "Server Key".encode('utf-8'), hashlib.sha256).digest()
_ = hashlib.sha256(s).digest()
d = "n=user,r="+u+",r="+i+",s="+a+",i="+str(o)+",c=biws,r="+i
g = hmac.new(_, d.encode('utf-8'), hashlib.sha256).digest()
p = hmac.new(c, d.encode('utf-8'), hashlib.sha256).digest()
f = bytes(a ^ b for (a, b) in zip(s, g))
proof = base64.b64encode(f).decode('utf-8')

step2 = {
  "transactionId": e,
  "proof": proof
}
step2 = json.dumps(step2)

url = BASE_URL + AUTH_FINISH
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step2, headers=headers)
response = json.loads(response.text)
token = response['token']
signature = response['signature']

y = hmac.new(_, "Session Key".encode('utf-8'), hashlib.sha256)
y.update(d.encode('utf-8'))
y.update(s)
P = y.digest()
protocol_key = P
t = os.urandom(16)

e2 = AES.new(protocol_key,AES.MODE_GCM,t)
e2, authtag = e2.encrypt_and_digest(token.encode('utf-8'))

step3 = {
  "transactionId": e,
  "iv": base64.b64encode(t).decode('utf-8'),
  "tag": base64.b64encode(authtag).decode("utf-8"),
  "payload": base64.b64encode(e2).decode('utf-8')
}
step3 = json.dumps(step3)

headers = { 'Content-type': 'application/json', 'Accept': 'application/json' }
url = BASE_URL + AUTH_CREATE_SESSION
response = requests.post(url, data=step3, headers=headers)
response = json.loads(response.text)
sessionId = response['sessionId']

#create a new header with the new Session-ID for all further requests
headers = { 'Content-type': 'application/json', 'Accept': 'application/json', 'authorization': "Session " + sessionId }
url = BASE_URL + ME
response = requests.get(url = url, headers = headers)
response = json.loads(response.text)
authOK = response['authenticated']
if not authOK:
    print("authorization NOT OK")
    sys.exit()

url = BASE_URL + "/info/version"
response = requests.get(url = url, headers = headers)
response = json.loads(response.text)
swversion = response['sw_version']
apiversion = response['api_version']
hostname = response['hostname']
name = response['name']
print("Connected to the inverter " + name + "/" + hostname + " with SW-Version " + swversion + " and API-Version " + apiversion)

# Auth OK, now send your desired requests

url = BASE_URL + request

response = requests.get(url = url, headers = headers)
response = json.loads(response.text)

message  = json.dumps(response)

#print(json.dumps(response, indent=4, sort_keys=True))
#print(message)


async def run():

    try:
        with open('/opt/fhem/python/pwd_fhem.json', 'r') as f:
            credentials=json.load(f)
    except Exception as e:
        print('Something went wrong: {}'.format(e))

    fh = fhem.Fhem(web, protocol="http", port=8083, username=credentials["username"], password=credentials["password"])

    fh.send_cmd("setreading PV_Anlage_1 statistics_output " + message)

asyncio.get_event_loop().run_until_complete(run())

'''Userreadings'''
Die userreadings gehören zum Gerät PV_Anlage_1 .

statistics_clean
   Trigger: statistics_output.*
   Dies ist ein temporäres reading, das nur als zwischen Schritt für die Erstellung der Statistics_* readings verwendet wird. Befüllt wird zuerst
   das reading statistics_output durch ein regelmäßig laufendes Python Skript. Auch dies wird noch später behandelt.
statistics_output
   Trigger: externes Python Skript
   Das userreading wird über ein Python Skript mit Daten gefüllt und dient als Trigger für statistics_clean

'''Passworte'''
Die Passworte für den Plenticore und den FHEM Zugang liegen in einzelnen JSON Dateien

fhem@raspberrypi:~/python$ cat pwd_plenticore.json
<pre>
{
    "username": "user",
    "password": "<Steht auf dem Gehäuse>"
}

fhem@raspberrypi:~/python$ cat pwd_fhem.json

{
    "username": "<Ein Fhem Telnet User>",
    "password": "<Das Passwort des Users>"
}

1.2 Einbindung in FHEM: KSEM mit MODBUS/TCP

Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.

Das Gerät ist hier mit "disable 1" konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.

Auch hier ist ein intervall von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.

- RAW Definition des KSEM

defmod PV_KSEM ModbusAttr 1 60 192.168.178.17:502 TCP
attr PV_KSEM DbLogExclude .*
attr PV_KSEM alias PV_Energy_Manager
attr PV_KSEM comment Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind.\
Alle nicht unterstützen Werte sind mit 0x8000 gekennzeichnet.\
Für die nicht unterstützten Zählerstände wird die 0x800000000 ausgegeben.\
\
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber\
berechnet werden aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current)\
\
Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.
attr PV_KSEM dev-h-defPoll 1
attr PV_KSEM dev-type-INT16-len 1
attr PV_KSEM dev-type-INT16-unpack s>
attr PV_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_Current_SF",0))
attr PV_KSEM dev-type-INT16_Current-format %.2f
attr PV_KSEM dev-type-INT16_Current-len 1
attr PV_KSEM dev-type-INT16_Current-unpack s>
attr PV_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_Freq_SF",0))
attr PV_KSEM dev-type-INT16_Freq-format %.2f
attr PV_KSEM dev-type-INT16_Freq-len 1
attr PV_KSEM dev-type-INT16_Freq-unpack s>
attr PV_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_PF_SF",0))
attr PV_KSEM dev-type-INT16_PF-format %.2f
attr PV_KSEM dev-type-INT16_PF-len 1
attr PV_KSEM dev-type-INT16_PF-unpack s>
attr PV_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_Power_SF",0))
attr PV_KSEM dev-type-INT16_Power-format %.2f
attr PV_KSEM dev-type-INT16_Power-len 1
attr PV_KSEM dev-type-INT16_Power-unpack s>
attr PV_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_VA_SF",0))
attr PV_KSEM dev-type-INT16_VA-format %.2f
attr PV_KSEM dev-type-INT16_VA-len 1
attr PV_KSEM dev-type-INT16_VA-unpack s>
attr PV_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_VAR_SF",0))
attr PV_KSEM dev-type-INT16_VAR-format %.2f
attr PV_KSEM dev-type-INT16_VAR-len 1
attr PV_KSEM dev-type-INT16_VAR-unpack s>
attr PV_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum("$name" ,"M_AC_Voltage_SF",0))
attr PV_KSEM dev-type-INT16_Voltage-format %.2f
attr PV_KSEM dev-type-INT16_Voltage-len 1
attr PV_KSEM dev-type-INT16_Voltage-unpack s>
attr PV_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr
attr PV_KSEM dev-type-STR32-format %s
attr PV_KSEM dev-type-STR32-len 16
attr PV_KSEM dev-type-STR32-unpack a*
attr PV_KSEM dev-type-UINT16-format %s
attr PV_KSEM dev-type-UINT16-len 1
attr PV_KSEM dev-type-UINT32-format %s
attr PV_KSEM dev-type-UINT32-len 2
attr PV_KSEM dev-type-UINT64-expr $val/10000
attr PV_KSEM dev-type-UINT64-format %s
attr PV_KSEM dev-type-UINT64-len 4
attr PV_KSEM dev-type-UINT64-unpack Q>
attr PV_KSEM disable 1
attr PV_KSEM group PV Eigenverbrauch
attr PV_KSEM icon measure_power
attr PV_KSEM obj-h40072-reading M_AC_Current_A
attr PV_KSEM obj-h40072-type INT16_Current
attr PV_KSEM obj-h40073-reading M_AC_Current_B
attr PV_KSEM obj-h40073-type INT16_Current
attr PV_KSEM obj-h40074-reading M_AC_Current_C
attr PV_KSEM obj-h40074-type INT16_Current
attr PV_KSEM obj-h40075-reading M_AC_Current_SF
attr PV_KSEM obj-h40075-type INT16
attr PV_KSEM obj-h40077-reading M_AC_Voltage_AN
attr PV_KSEM obj-h40077-type INT16_Voltage
attr PV_KSEM obj-h40078-reading M_AC_Voltage_BN
attr PV_KSEM obj-h40078-type INT16_Voltage
attr PV_KSEM obj-h40079-reading M_AC_Voltage_CN
attr PV_KSEM obj-h40079-type INT16_Voltage
attr PV_KSEM obj-h40084-reading M_AC_Voltage_SF
attr PV_KSEM obj-h40084-type INT16
attr PV_KSEM obj-h40085-reading M_AC_Freq
attr PV_KSEM obj-h40085-type INT16_Freq
attr PV_KSEM obj-h40086-reading M_AC_Freq_SF
attr PV_KSEM obj-h40086-type INT16
attr PV_KSEM obj-h40087-reading M_AC_Power
attr PV_KSEM obj-h40087-type INT16_Power
attr PV_KSEM obj-h40088-reading M_AC_Power_A
attr PV_KSEM obj-h40088-type INT16_Power
attr PV_KSEM obj-h40089-reading M_AC_Power_B
attr PV_KSEM obj-h40089-type INT16_Power
attr PV_KSEM obj-h40090-reading M_AC_Power_C
attr PV_KSEM obj-h40090-type INT16_Power
attr PV_KSEM obj-h40091-reading M_AC_Power_SF
attr PV_KSEM obj-h40091-type INT16
attr PV_KSEM obj-h40092-reading M_AC_VA
attr PV_KSEM obj-h40092-type INT16_VA
attr PV_KSEM obj-h40093-reading M_AC_VA_A
attr PV_KSEM obj-h40093-type INT16_VA
attr PV_KSEM obj-h40094-reading M_AC_VA_B
attr PV_KSEM obj-h40094-type INT16_VA
attr PV_KSEM obj-h40095-reading M_AC_VA_C
attr PV_KSEM obj-h40095-type INT16_VA
attr PV_KSEM obj-h40096-reading M_AC_VA_SF
attr PV_KSEM obj-h40096-type INT16
attr PV_KSEM obj-h40097-reading M_AC_VAR
attr PV_KSEM obj-h40097-type INT16_VAR
attr PV_KSEM obj-h40098-reading M_AC_VAR_A
attr PV_KSEM obj-h40098-type INT16_VAR
attr PV_KSEM obj-h40099-reading M_AC_VAR_B
attr PV_KSEM obj-h40099-type INT16_VAR
attr PV_KSEM obj-h40100-reading M_AC_VAR_C
attr PV_KSEM obj-h40100-type INT16_VAR
attr PV_KSEM obj-h40101-reading M_AC_VAR_SF
attr PV_KSEM obj-h40101-type INT16
attr PV_KSEM obj-h40102-reading M_AC_PF
attr PV_KSEM obj-h40102-type INT16_PF
attr PV_KSEM obj-h40103-reading M_AC_PF_A
attr PV_KSEM obj-h40103-type INT16_PF
attr PV_KSEM obj-h40104-reading M_AC_PF_B
attr PV_KSEM obj-h40104-type INT16_PF
attr PV_KSEM obj-h40105-reading M_AC_PF_C
attr PV_KSEM obj-h40105-type INT16_PF
attr PV_KSEM obj-h40106-reading M_AC_PF_SF
attr PV_KSEM obj-h40106-type INT16
attr PV_KSEM obj-h40108-reading M_Exported
attr PV_KSEM obj-h40108-type UINT32
attr PV_KSEM obj-h40110-reading M_Exported_A
attr PV_KSEM obj-h40110-type UINT32
attr PV_KSEM obj-h40112-reading M_Exported_B
attr PV_KSEM obj-h40112-type UINT32
attr PV_KSEM obj-h40114-reading M_Exported_C
attr PV_KSEM obj-h40114-type UINT32
attr PV_KSEM obj-h40116-reading M_Imported
attr PV_KSEM obj-h40116-type UINT32
attr PV_KSEM obj-h40118-reading M_Imported_A
attr PV_KSEM obj-h40118-type UINT32
attr PV_KSEM obj-h40120-reading M_Imported_B
attr PV_KSEM obj-h40120-type UINT32
attr PV_KSEM obj-h40122-reading M_Imported_C
attr PV_KSEM obj-h40122-type UINT32
attr PV_KSEM obj-h40125-reading M_Exported_VA
attr PV_KSEM obj-h40125-type UINT32
attr PV_KSEM obj-h40127-reading M_Exported_VA_A
attr PV_KSEM obj-h40127-type UINT32
attr PV_KSEM obj-h40129-reading M_Exported_VA_B
attr PV_KSEM obj-h40129-type UINT32
attr PV_KSEM obj-h40131-reading M_Exported_VA_C
attr PV_KSEM obj-h40131-type UINT32
attr PV_KSEM obj-h40133-reading M_Imported_VA
attr PV_KSEM obj-h40133-type UINT32
attr PV_KSEM obj-h40135-reading M_Imported_VA_A
attr PV_KSEM obj-h40135-type UINT32
attr PV_KSEM obj-h40137-reading M_Imported_VA_B
attr PV_KSEM obj-h40137-type UINT32
attr PV_KSEM obj-h40139-reading M_Imported_VA_C
attr PV_KSEM obj-h40139-type UINT32
attr PV_KSEM obj-h512-reading Active_energy+
attr PV_KSEM obj-h512-type UINT64
attr PV_KSEM obj-h516-reading Active_energy-
attr PV_KSEM obj-h516-type UINT64
attr PV_KSEM obj-h8192-reading ManufacturerID
attr PV_KSEM obj-h8192-type UINT16
attr PV_KSEM obj-h8193-reading ProductID
attr PV_KSEM obj-h8193-type UINT16
attr PV_KSEM obj-h8194-reading ProductVersion
attr PV_KSEM obj-h8194-type UINT16
attr PV_KSEM obj-h8195-reading FirmwareVersion
attr PV_KSEM obj-h8195-type UINT16
attr PV_KSEM obj-h8196-reading VendorName
attr PV_KSEM obj-h8196-type STR32
attr PV_KSEM obj-h8212-reading Productname
attr PV_KSEM obj-h8212-type STR32
attr PV_KSEM obj-h8228-reading SerialNumber
attr PV_KSEM obj-h8228-type STR32
attr PV_KSEM obj-h8244-reading MeasuringInterval
attr PV_KSEM obj-h8244-type UINT16
attr PV_KSEM room Strom->Photovoltaik
attr PV_KSEM sortby 03
attr PV_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,"M_AC_Current_A",0) + ReadingsVal($NAME,"M_AC_Current_B",0) + ReadingsVal($NAME,"M_AC_Current_C",0) }
attr PV_KSEM verbose 0

1.3 Einbindung in FHEM: BYD Speicher (über Python Skript)

Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.


2. PV Eigenverbrauch-Steuerung

Beispiel Luft Wärme Pumpe - RAW Definition LWP_LuftWärmePumpe (dummy Modul)

defmod LWP dummy
attr LWP DbLogExclude .*
attr LWP DbLogInclude state
attr LWP alias LWP_LuftWärmePumpe
attr LWP group PV Eigenverbrauch
attr LWP icon sani_earth_source_heat_pump
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd
attr LWP room Strom->Photovoltaik
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time
attr LWP sortby 05
attr LWP stateFormat state
attr LWP verbose 0
attr LWP webCmd LWP_Button

- RAW Definition LWP_PV (DOIF Modul)

defmod LWP_PV DOIF ################################################################################################################\
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\
##\
    ([LWP_Counter:pulseTimePerDay] >= [LWP:RunTimePerDay] and\
     [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
     [LWP:state] ne "off" and [LWP:LWP_Button] eq "off" )\
\
    ({Log 3, " LWP_PV cmd_1 PV : LWP off"}\
     {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
     {fhem("set LWP off")}\
     {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\
##\
DOELSEIF\
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) < [LWP:PowerLimitOff] and\
     [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
     [LWP:state] ne "off" and\
     [LWP:LWP_Button] ne "on" )\
\
    ({Log 3, " LWP_PV cmd_2 PV : LWP off"}\
     {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
     {fhem("set LWP off")}\
     {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\
##   wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\
##\
DOELSEIF\
    ([PV_Anlage_1:Total_PV_Power_reserve] < [LWP:PowerLimitOff] and\
     [LWP_PV:wait_timer] ne "no timer" and\
     [LWP_PV:wait_timer] ne "" and\
     [LWP:state] eq "off" )\
\
    ({Log 3, "LWP_PV cmd_3 PV : Stop wait timer LWP"})\
################################################################################################################\
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\
##\
DOELSEIF\
    ([Astro:ObsSeason] ne "Sommer" and [Astro:ObsSeason] ne "Frühling" and\
     [PV_Anlage_1:Total_PV_Power_reserve] >= [LWP:PowerLimitOn] and\
     [[LWP:TimeStart]-[LWP:TimeEnd]] and\
     [LWP:state] eq "off" and\
     [LWP_Counter:pulseTimePerDay] < [LWP:RunTimePerDay] and\
     [Heizung:hotWaterTemperature] < 60 )\
\
    ({Log 3, "LWP_PV cmd_4 : LWP on"}\
     {fhem("".ReadingsVal("LWP","SetCmdOn",0))}\
     {fhem("set LWP on")}\
     {fhem("set Heizung hotWaterTemperatureTarget 60.0")}\
    )\
################################################################################################################\
## 5 Signal für den PV-Modus der LWP einschalten.\
##\
DOELSEIF\
    ([LWP:LWP_Button] eq "on" )\
\
    ({Log 3, "LWP_PV cmd_5 PV : LWP on for manuel PV-Modus"}\
     {fhem("".ReadingsVal("LWP","SetCmdOn",0))}\
     {fhem("set LWP on")}\
     {fhem("set Heizung hotWaterTemperatureTarget 60.0")}\
     )\
################################################################################################################\
## 6 Signal für den PV-Modus der LWP abschalten.\
##\
DOELSEIF\
    ([LWP:LWP_Button] eq "off" and\
     [$SELF:cmd_nr] eq "5"  )\
\
    ({Log 3, "LWP_PV cmd_6 PV : LWP off after manuel PV-Modus"}\
     {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
     {fhem("set LWP off")}\
     {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
    )\
################################################################################################################\
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\
##\
DOELSEIF\
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] > 300 and\
    [Heizung:opStateHeatPump1] eq "Wärmepumpe kommt" and\
    [Heizung:opStateHeatPump3] eq "Pumpenvorlauf" )\
\
     ({Log 3, "LWP_PV cmd_7 : Stop wait timer LWP"})\
################################################################################################################\
## 8 LWP Ende\
##\
DOELSEIF\
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] < 300 and\
    [LWP_Counter:pulseTimeIncrement] >= [LWP:RunTimeMin] and\
    ([Heizung:opStateHeatPump1] ne "Wärmepumpe läuft" or [Heizung:opStateHeatPump3] eq "Luftabtauen" ) and\
    ([$SELF:cmd_nr] eq "4" or [$SELF:cmd_nr] eq "5" or [$SELF:cmd_nr] eq "10") )\
\
    ({Log 3, "LWP_PV cmd_8 : LWP run finished"}\
     {fhem("".ReadingsVal("LWP","SetCmdOff",0))}\
     {fhem("set LWP off")}\
     {fhem("set Heizung hotWaterTemperatureTarget 50.0")}\
     {fhem("setreading LWP LWP_Button off")}\
    )\
################################################################################################################\
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\
##   Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\
##\
DOELSEIF\
   ([Astro:ObsSeason] ne "Sommer" and [Astro:ObsSeason] ne "Frühling" and\
    [[LWP:TimeEnd]] and\
    [Heizung:hotWaterTemperature] < 47 and\
    ([LWP_Counter:pulseTimePerDay] < [Pool:RunTimePerDay] or\
     [LWP_Counter:countsPerDay] eq 0) )\
\
    ({Log 3, "LWP_PV cmd_9 : LWP on for water heating"}\
\
     {fhem("set Heizung hotWaterTemperatureTarget ". (ReadingsVal("Heizung","hotWaterTemperature",46)+4))}\
\
     {Log 3, "LWP_PV cmd_9 : LWP hotWaterTemperatureTarget ".ReadingsVal("Heizung","hotWaterTemperatureTarget",0)}\
    )\
################################################################################################################\
## 10 Hohe Priorität im Winter fuer die LWP\
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\
##\
DOELSEIF\
    ([Astro:ObsSeason] eq "Winter" and\
     [PV_Anlage_1:Total_PV_Power_reserve] >= 2000 and\
     [shelly02:power_0] > 800 and\
     [PV_Anlage_1:Act_state_of_charge] > 60 and\
     [Heizung:hotWaterTemperature] < 60 and \
     [$SELF:cmd_nr] ne "10" )\
\
    ({Log 3, "LWP_PV cmd_10 : LWP Priorität"}\
     {fhem("set LWP_PV cmd_4")}\
    )\

attr LWP_PV DbLogExclude .*
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer
attr LWP_PV alias LWP_PV
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität
attr LWP_PV do always
attr LWP_PV group PV Eigenverbrauch-Steuerung
attr LWP_PV icon sani_earth_source_heat_pump
attr LWP_PV room Strom->Photovoltaik
attr LWP_PV sortby 01
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C
attr LWP_PV userReadings LWP_Status { ReadingsVal("Heizung","state","") }
attr LWP_PV verbose 5
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0

- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)

defmod shelly01 Shelly 192.168.178.55
attr shelly01 DbLogExclude .*
attr shelly01 DbLogInclude relay.*,power.*,energy.*
attr shelly01 alias LWP_Signale
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network
attr shelly01 group PV Eigenverbrauch-Steuerung
attr shelly01 icon taster_ch_1
attr shelly01 mode relay
attr shelly01 model shelly1pm
attr shelly01 room Shelly,Heizung->System,Strom->Photovoltaik
attr shelly01 sortby 02
attr shelly01 stateFormat {sprintf("\
<TABLE>\
\
<TR>\
  <TD VALIGN=\"TOP\" ALIGN=\"LEFT\" WIDTH=\"50\">\
    WebLink: %s\
  </TD>\
\
  <TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"100\">\
    Gesamt 0: %08.2f KWh<br>\
  </TD>\
\
  <TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"70\">\
    Relais 0: %s %06.1f Watt<br>\
  </TD>\
</TR>\
\
</TABLE>\
" ,\
ReadingsVal($name,"WebLink","none") ,\
ReadingsVal($name,"energy_0",0)/1000,\
(ReadingsVal($name,"relay","") eq "off") ? "<span style='color:#FF0000'>off</span>":"<span style='color:#00FF00'>on</span>",\
ReadingsVal($name,"power",0),\
)}
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,"network","");; $ip =~ s/connected to //gs;; $ip =~ s/<[^>]*>//gs;; return("<html><a href='http://".$ip."/'>WEB</a></html>") }
attr shelly01 webCmd |

- RAW Definition LWP_Counter (HourCounter Modul)


- RAW Definition rg_LWP_Status (readingsGroup Modul)


Beispiel Pool - RAW Definition Pool_Softube (dummy Modul)


- RAW Definition Pool_PV (DOIF Modul)


- RAW Definition Pool_Signale (Shelly Modul: shelly1pm)


- RAW Definition Pool_Counter (HourCounter Modul)


- RAW Definition rg_Pool_Status (readingsGroup Modul)


Beispiel Waschmaschine (mit Walzenschalter ;-) ) - RAW Definition Waschmaschine (dummy Modul)


- RAW Definition Waschmaschine_PV (DOIF Modul)


- RAW Definition Waschmaschine_Signale (Shelly Modul: shelly2.5)


- RAW Definition Waschmaschine_Counter (HourCounter Modul)


- RAW Definition rg_Waschmaschine_Status (readingsGroup Modul)



3. Energie Bilanz

- RAW Definition Energiebilanz


Erstellen von zusätzlichen Werten in der Datenbank Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft.

- RAW Definition LogDBRep_PV_total_diff_Week


- RAW Definition LogDBRep_PV_total_max_Month


- RAW Definition LogDBRep_PV_used_diff_Week


- RAW Definition LogDBRep_PV_used_max_Month


Löschen von nicht mehr benötigten Werten in der Datenbank Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen. Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.


4. Wetter Prognose

5. Diagramme

- RAW Definition Leistungsuebersicht - SVG_LogDB_Photovoltaik_1


- RAW Definition Hauptverbraucher - SVG_LogDB_Photovoltaik_2


- RAW Definition Leistungsbezug - SVG_LogDB_Photovoltaik_3


- RAW Definition PV_Bilanz - SVG_LogDB_PV_Bilanz


- RAW Definition Forecast / Calculation - SVG_LogDB_Photovoltaik_4



Problemlösung

Projekte der FHEM-Community

  • Beitrag - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)
  • Beitrag - Kostal Plenticore Bilanz
  • Beitrag - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast
  • Thema - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)
  • Thema - Neue Version von HTTPMOD mit neuen Features zum Testen

Links