[36_Senec.pm] FHEM module zur Integration eines SENEC Speicher und MeinSenec

Begonnen von carlos, 12 November 2021, 15:22:44

Vorheriges Thema - Nächstes Thema

FHEM@UL

Hallo zusammmen,
ich habe leider Probleme mit der Einbindung des 36_Senec.pm Modul, vermutlich ein Anfängerproblem. Ich bekomme diese folgende Fehlermeldung, wenn ich das Modul mittels "reload" in FHEM integrieren möchte.

Can't locate DateTime/Format/ISO8601.pm in @INC (you may need to install the DateTime::Format::ISO8601 module) (@INC contains: ./lib ./FHEM . /etc/perl /usr/local/lib/aarch64-linux-gnu/perl/5.36.0 /usr/local/share/perl/5.36.0 /usr/lib/aarch64-linux-gnu/perl5/5.36 /usr/share/perl5 /usr/lib/aarch64-linux-gnu/perl-base /usr/lib/aarch64-linux-gnu/perl/5.36 /usr/share/perl/5.36 /usr/local/lib/site_perl ./FHEM/lib) at ./FHEM/36_Senec.pm line 57.
BEGIN failed--compilation aborted at ./FHEM/36_Senec.pm line 57.

Kann mir jemand bitte weiterhelfen. Vielen Dank

carlos

Hallo
1. Hier steht: you may need to install the DateTime::Format::ISO8601 module dann ist das Problem gelöst.
2. Im Moment ist das Modul nicht nutzbar, da SENEC die Anmeldung geändert hat.
3. Es wird auch keine neue Version von mir mehr geben, da mein Senec demnächst abgebaut wird.

Gruß

Hubert
FHEM svn auf Intel NUC mit proxmox, 3 Raspberry Pi, signalduino, nanoCUL,  toom Baumarkt Funksteckdosen, einige sonoffs, hue, shelly

Bobby

Hallo,

hat es irgendwer hinbekommen und die aktuelle Version wieder zum laufen gebracht?

Grüße Thomas

cnkru

Ich habe mich auch mit verschiedenen Lösungen beschäftigt.
Zuletzt mit iobroker und Homeassistant - nun nutze ich verschiedene eigene Scripts...

Die Momentanwerte lese per Readings und HTTPMOD aus - siehe unten
Dies wurde auch im Forum schon oft dokumentiert (z.B. Auslesen SENEC-Batterie etc.)


defmod SENEC_State HTTPMOD https://192.xxx.xxx.xxx//Vars.html 600
attr SENEC_State alias SENEC_State
attr SENEC_State enableControlSet 1
attr SENEC_State reading01JSON PV1_POWER_RATIO
attr SENEC_State reading01Name PV-Begrenzung
attr SENEC_State reading01OExpr {hex( (split ('_',$val,0 ))[1] )}
attr SENEC_State reading02JSON ENERGY_GUI_INVERTER_POWER
attr SENEC_State reading02Name PV-Erzeugung
attr SENEC_State reading02OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading03JSON ENERGY_GUI_BAT_DATA_FUEL_CHARGE
attr SENEC_State reading03Name AKKU-Beladung
attr SENEC_State reading03OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading04JSON ENERGY_GUI_BAT_DATA_POWER
attr SENEC_State reading04Name AKKU-Entnahme
attr SENEC_State reading04OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading05JSON ENERGY_GUI_HOUSE_POW
attr SENEC_State reading05Name Haus-Stromverbrauch
attr SENEC_State reading05OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading06JSON PM1OBJ1_P_TOTAL
attr SENEC_State reading06Name Netz-Einspeisung
attr SENEC_State reading06OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading07JSON ENERGY_STAT_STATE
attr SENEC_State reading07Name PV-Status
attr SENEC_State reading07OExpr {hex( (split ('_',$val,0 ))[1] )}
attr SENEC_State reading08JSON BMS_VOLTAGE
attr SENEC_State reading08Name BatterieSpannung
attr SENEC_State reading08OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading09JSON BMS_CURRENT
attr SENEC_State reading09Name BatterieStrom
attr SENEC_State reading09OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading10JSON BMS_CYCLES
attr SENEC_State reading10Name BatterieZyklen
attr SENEC_State reading10OExpr {hex( (split ('_',$val,0 ))[1] )}
attr SENEC_State reading11JSON PV1_MPP_VOL
attr SENEC_State reading11Name ModulSpannung
attr SENEC_State reading11OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading12JSON PV1_MPP_CUR
attr SENEC_State reading12Name ModulStrom
attr SENEC_State reading12OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading13JSON PV1_MPP_POWER
attr SENEC_State reading13Name ModulLeistung
attr SENEC_State reading13OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading14JSON TEMPMEASURE_BATTERY_TEMP
attr SENEC_State reading14Name Temperatur_Batterie
attr SENEC_State reading14OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading15JSON TEMPMEASURE_CASE_TEMP
attr SENEC_State reading15Name Temperatur_Gehaeuse
attr SENEC_State reading15OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State reading16JSON TEMPMEASURE_MCU_TEMP
attr SENEC_State reading16Name Temperatur_Hardware
attr SENEC_State reading16OExpr {sprintf("%.2f", unpack "f", pack "L", hex ((split('_',$val,0))[1]),0)}
attr SENEC_State requestData {"PV1":{"POWER_RATIO":"","MPP_VOL":"","MPP_CUR":"","MPP_POWER":""},"ENERGY":{"GUI_HOUSE_POW":"","GUI_INVERTER_POWER":"","GUI_BAT_DATA_POWER":"","GUI_BAT_DATA_FUEL_CHARGE":"","STAT_STATE":""},"PM1OBJ1":{"P_TOTAL":""},"STATISTIC":{"CURRENT_STATE":""},"BMS":{"VOLTAGE":"","CURRENT":"","CYCLES":""},"TEMPMEASURE":{"BATTERY_TEMP":"","CASE_TEMP":"","MCU_TEMP":""}}
attr SENEC_State room SENEC
attr SENEC_State showBody 1
attr SENEC_State timeout 4

Für die Tages-Daten verwende ich ein python-script, welches diese stündlich aus der SENEC-Cloud ausliest.
Die Idee stammt aus dieser Quelle: https://github.com/marq24/ha-senec-v3/discussions/155 - Vielen Dank an Matthias Marquardt!

import requests
import json
import logging

_SENEC_USERNAME = "Username" # your senec login username
_SENEC_PASSWORD = "Password" # your senec password

_SENEC_OAUTH2_URL = "https://mein-senec.de/endkunde/oauth2/authorization/endkunde-portal"
_SENEC_API_URL_START="https://mein-senec.de/endkunde/api/status/getstatusoverview.php?type="
#_SENEC_API_URL_START="https://mein-senec.de/endkunde/api/status/getstatus.php?type=" //alte Variante
_SENEC_API_URL_END="&period=all&anlageNummer=0"

logging.basicConfig(level=logging.INFO) #logging.INFO
logger = logging.getLogger(__name__)

_session = requests.Session()

# First we start with the OAuth2 URL of mein-senec.de
r = _session.post(_SENEC_OAUTH2_URL, timeout=10)

logger.info("Status Code: " + str(r.status_code))

# We've been redirected to the login page on sso.senec.com.
# Now we need to find the URL the login form uses:

# The form has the id "kc-form-login", so lets jump to that:
s = r.text[r.text.find('kc-form-login'):]

# Then cut everything away until the actual post URL starts:
s = s[s.find('action="')+8:]

# And cut away everything after the post URL:
s = s[:s.find('" method=')]

# This should output the post URL:
logger.info("Text: " + s)

logger.info("----------------------------------")

# Now we use the extracted URL to log in with our usual credentials:
auth_payload = {
    "username" : _SENEC_USERNAME,
    "password" : _SENEC_PASSWORD
}
r = _session.post(s, auth_payload, timeout=10)

logger.info("Status Code: " + str(r.status_code))
# This should be the normal landing page once logged into mein-senec.de:
#logger.info("Text: " + r.text)

logger.info("----------------------------------")
# And here we poll the total value of accuimport as a test:
logger.info("accuimport:")

key = "accuimport"

api_url = _SENEC_API_URL_START + key + _SENEC_API_URL_END
r=_session.get(api_url, timeout=10)
logger.info("Status Code: " + str(r.status_code))
if r.status_code==200:
    logger.info(r.text)

##end
 
Die Ausgabe erfolgt auf stdin bzw. stdout.
Die Daten werden dann, wie folgt in FHEM abgerufen...
fhem("{system('python /opt/fhem/senec.py 2>/opt/fhem/www/input.txt &')}; sleep 6; {senec_tag_summe_py()}");

Die Auftrennung in 2 Routinen habe ich bewusst gewählt, da oft ein Timmeout (bis zu 5 Sek.) oder Freeze des FHEM
beim Auslesen der SENEC-Cloud auftrat.
Daher die Entkopplung, um mein FHEM-System nicht zu blockieren.

Bleibt noch das Perl-Script für die Ermittlung der Tageswerte (hier die Quick&Dirty-Variante).

#!/usr/bin/perl -w

use strict;
use LWP::Simple;
sub senec_tag_summe()
{
my $org_result="";
my $result="";
my $wert="";
my $l1=0;
my $l2=0;
my $len=0;
my $gridimp="gridimport";
my $today="today";
my $now ="now";
$org_result=qx(python ./senec.py 2>&1);
print $org_result."\n";
$l1=index($org_result,"gridimport");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1); 

print $result."\n";
print $len."\n";

$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert."\n";

$l1=index($org_result,"powergenerated");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1);
$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert." powergenerated \n";

$l1=index($org_result,"consumption");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1);
$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert." consumtion \n";

$l1=index($org_result,"gridexport");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1);
$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert." gridexport \n";

$l1=index($org_result,"accuexport");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1);
$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert." accuexport \n";

$l1=index($org_result,"accuimport\"");
print $l1."\n";
$len = length($org_result);
print $len."\n";
$result = substr($org_result, $l1, $len-$l1-1);
$l1=index($result,$today)+7;
$l2=index($result,$now)-2;
$wert = substr($result,$l1,($l2-$l1));
print $result."\n";
print $wert." accuimport \n";


}
senec_tag_summe();


LG
cnkru

RPi4, Razberry, ZWAVE (Thermostate, Dimmer, Schalter, Multisensor), Milight-LED, Wifi (IPCAM, Fritz!DECT, Sonoff), alexa, Hombridge, Velux-Rollos, Viessman-API, iobroker, SENEC

Uwe Ernst

Hallo cnkru
Ich versuche dein Senec Tagesdaten umzusetzen. Ich kenne mich in python und perl nicht besonders gut aus, deshalb fehlen mir einige Infos zur Umsetzung.
Ich habe eine Datei /opt/fhem/senec.py erzeugt und den Inhalt aus deinem 2. Code eingefügt. Rechte sind gesetzt.
Jetzt meine Frage: in welche Datei und in welchen Ordner kommt dein 4. Code (perl)?
Beim Aufruf:fhem("{system('python /opt/fhem/senec.py 2>/opt/fhem/www/input.txt &')}; sleep 6; {senec_tag_summe_py()}");  -----(in Fhem)
erhalte ich die Fehlermeldung: Unknown command fhem("{system('python, try help.
Was ist mein Fehler.

HGButte

Hallo Senec Nutzer,


Da ich beim SenecV3 Speicher noch an meine aktuellen Daten komme waren mir die restlichen Infos gar nicht so wichtig.
Durch @cnkru's Beitrag getriggert, habe ich das Thema doch mal in Angriff genommen.

Ich arbeite gerade an der Umstellung dieses Moduls an die neuen Anmeldeverfahren und APIs.
Grundsätzlich funktioniert schon so gut wie alles.
Eine Senec Wallbox habe ich selbst nicht. Daher muss ich mal schauen was ich so im "Blindflug" oder mit eurer Hilfe hinbekomme.

Zwei Themen die ich noch bearbeiten möchte, bevor ich das Modul hier rein stelle:
  • Asynchrone Abfrage der Senec API um FHEM nicht zulange zu blockieren
  • Nicht bei jeder Abfrage eine neue "Anmeldung" bei Senec zu machen, sondern nur wenn nötig.

Bitte noch etwas Geduld.