#################################################################################################################
# $Id: 76_SMAEVCharger.pm 26639 2022-11-01 15:10:36Z jual $
# 76_SMAEVCharger.pm author: Jürgen Allmich
#################################################################################################################
#
#  Copyright notice
#
#  Published according Creative Commons : Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
#  Details: https://creativecommons.org/licenses/by-nc-sa/3.0/
#
#  Credits:
#  - used 73_SMAInverter.pm as template
#  - 
#  - 
#  - 
#  - 
#
#  Description:
#  This is an FHEM-Module for SMA EV Chargers.
#
#################################################################################################################
#
#  	Date			Version		Description
#	31.10.2022		0.0.93		Parameter AC-Strom_Begrenzung, Param_Manuelle_Ladefreigabe; Param_Ladefreigabe_ueber_App hinzugefügt; User & Passwort encrypted und Funktion get_Account hinzugefügt
#	22.01.2022		0.0.92		Bugfixes: insert 'use JSON'
#	12.12.2021		0.0.91		Bugfixes: check for undefined parameter in SMAEVCharger_getReadableCode($)
#	14.11.2021		0.0.9		Bugfixes: when setting an incorrect value, the set command was executed anyway. No there is no setting, if value are incorrect
#								Error on setting Laden_mit_Vorgabe while values Param_Energiemenge_Ladevorgang and Param_Dauer_Ladevorgang are set correctly
#								On logon, if there is no body or header now an error will be returned (otherwise some fhem may be killed)
#								Value "Schnellladen" on setting is not possible so it has been deleted from the options for Param_Betriebsart_Ladevorgang
#	05.07.2021		0.0.8		Bugfixing (Warnings of uninitialized values), Added Livedata "Drehschalter"
#	07.02.2021		0.0.7		'Schnellabschaltung' change detail-level to 0, Documentation for the module
#	30.01.2021		0.0.6		Attr setting-level, Setting Readings for advanced and expert, on setting Lademenge set correct end_time
#	24.01.2021		0.0.5		Bug fixing and new Readings Startzeit_Ladung, Anzahl_Ladevorgaenge, 
#								Attr detail-level for config which values the use would like to see (0: basic, 1: advanced, 2: expert)
#	14.01.2021		0.0.4		Set cmd for all charging values
#	11.01.2021		0.0.3		Read Params (not all), Set all values for charging
#	10.01.2021		0.0.2		Read Live Data
#	09.01.2021		0.0.1		Initial Modul
#
#
#################################################################################################################
#
#	Todos
#	Maybe Timesheets for automated charging (Weekplan) would be nice (actual solution with doif)
#	Integration user function for individual SOC Modules (trying first with my kia)
#	Look for better coding
#
#################################################################################################################

package main;

use strict;
use warnings;
eval "use DateTime;1"         or my $MissModulDateTime = "DateTime";
use Time::HiRes qw(gettimeofday tv_interval);
use Blocking;
use Time::Local;
use JSON;
use Encode qw(encode_utf8 decode_utf8);


###############################################################
#   SMAEVCharger - help functions and variables
###############################################################

# These readings are updateble
my %update_readings = (
	"Param_Betriebsart_Ladevorgang" 				=> {values => ":Optimiertes_Laden,Laden_mit_Vorgabe,Ladestopp", 	level => 0},
	"Param_Minimaler_Ladestrom" 					=> {values => ":slider,6,1,32", 												level => 0},
	"Param_Dauer_Ladevorgang" 						=> {values => ":time", 															level => 0},
	"Param_Energiemenge_Ladevorgang" 				=> {values => ":slider,1,1,100", 												level => 0},
	"Param_Manuelle_Ladefreigabe" 					=> {values => ":Ladesperre,Ladefreigabe", 										level => 0},
	"Param_Ladefreigabe_ueber_App" 					=> {values => ":ja,nein", 														level => 0},
	#"Param_Ende_Ladevorgang" => {values => "",  will be calculated with Param_Dauer_Ladevorgang but could also be set an Param_Dauer_Ladevorgang will be calculated
	
	#advanced
	"Param_Minimale_Schaltdauer_Relais"				=> {values => ":slider,0,5,600", 												level => 1},
	"Param_Trennung_nach_Vollladung" 				=> {values => ":ja,nein", 														level => 1},
	"Param_Ladebereitschaft_bis_Trennung" 			=> {values => "", 																level => 1},
	"Param_Betrieb_mit_Netzanschlusspunktzaehler" 	=> {values => ":ja,nein", 														level => 1},
	"Param_Nennstrom_Netzanschluss" 				=> {values => ":slider,0,1,100", 												level => 1},
	"Param_Nennwirkleistung_WMaxOut" 				=> {values => ":slider,1380,230,22000", 										level => 1},
	"Param_Nennwirkleistung_WMaxIn" 				=> {values => ":slider,1380,230,22000", 										level => 1},
	"Param_Maximale_Schieflast" 					=> {values => ":slider,0,230,10000", 											level => 1},
	"Param_Fallback_Wirkleistungsbegrenzung" 		=> {values => ":slider,0,230,22000", 											level => 1},
	"Param_AC_Strom_Begrenzung_AcALim" 				=> {values => ":slider,6,1,32", 												level => 1},

	
	#expert
	"Param_Timeout_nach_Kommunikationsverlust" 		=> {values => ":slider,200,100,60000",											level => 2},
	"Param_IGMP_Query_Intervall" 					=> {values => ":slider,11,10,31744",											level => 2},
	"Param_Auto_Update_an" 							=> {values => ":ja,nein",														level => 2},
	"Param_Geraeteneustart_ausloesen" 				=> {values => ":---,Ausführen",													level => 2},
	"Param_WLAN_suchen" 							=> {values => ":---,Scan-durchführen",											level => 2},
	"Param_WPS_aktivieren" 							=> {values => ":---,WPS-aktivieren",											level => 2},
	"Param_WLAN_eingeschaltet" 						=> {values => ":ja,nein",														level => 2},
	"Param_Verschluesselung_WLAN"  					=> {values => ":WPA2-MIXED,WPA,WPA2",											level => 2},
	"Param_WLAN-Passwort" 							=> {values => "",																level => 2},
	"Param_SSID_WLAN" 								=> {values => "",																level => 2},
	"Param_Soft_Access_Point_an" 					=> {values => ":ja,nein",														level => 2},
	);
	
	
my %reading_codes = (
	"Optimiertes_Laden" => "4719",
	"Laden_mit_Vorgabe" => "4720",
	"Schnellladen" => "4718",
	"Ladestopp" => "4721",
	"ja" => "1129",
	"nein" => "1130",
	"nicht verbunden" => "200111",
	"verbunden" => "200112",
	"Ladevorgang aktiv" => "200113",
	"Phase L1 L2 L3" => "326",
	"---" => "302",
	"Ok" => "307",
	"Ein" => "308",
	"Ausführen" => "1146",
	"Scan-durchführen" => "3342",
	"WPS-aktivieren" => "3321",
	"WPA" => "3323",
	"WPA2" => "3324",
	"WPA2-MIXED" => "3398",
	"intelligente Ladung" => "4950",
	"Ladesperre" => "5171",
	"Ladefreigabe" => "5172"
	);

###############################################################
#                  SMAEVCharger getReadableCode
###############################################################
sub SMAEVCharger_getReadableCode($)
{
	my ($code) = @_;

	if(defined($code))
	{
		foreach my $key (keys %reading_codes)
		{
			if($reading_codes{$key} eq $code)
			{
				return $key;
			}
		}
	
		return $code;
	}
	else
	{
		return '';
	}
}

###############################################################
#                  SMAEVCharger getReadingCode
###############################################################
sub SMAEVCharger_getReadingCode($)
{
	my ($readable_code) = @_;

	if(defined($reading_codes{$readable_code}))
	{
		return $reading_codes{$readable_code};
	}
	else
	{
		return $readable_code;
	};
}


###############################################################
#                  SMAEVCharger checkPossibleValue
###############################################################
sub SMAEVCharger_checkPossibleValues($$$)
{
	my ($name, $reading,$val) = @_;

	my $return = undef;
	
	Log3 $name, 4, "$name -> Check if values are in range";
	
	if ($reading eq "Param_Betriebsart_Ladevorgang" and $val == 4720 and 
		(ReadingsVal($name,"Param_Dauer_Ladevorgang", "0") == 0 
		or ReadingsVal($name,"Param_Energiemenge_Ladevorgang", "0") == 0
		or ReadingsVal($name,"Status_Ladevorgang", "nicht verbunden") eq 'nicht verbunden'))
	{
		if(ReadingsVal($name,"Status_Ladevorgang", "nicht verbunden") eq 'nicht verbunden')
		{
			$return = "Car is not connected to the charger";
		}
		else
		{
			$return = "Please first set values Param_Energiemenge_Ladevorgang and Param_Dauer_Ladevorgang";
		}
	}
	elsif ((my $min = ReadingsVal($name,".".$reading."_min", "ERR")) ne "ERR")
	{
		Log3 $name, 4, "$name -> Check for min / max:".$reading.":".$val." min=".$min;
		
		if ($val >= $min and $val <= ReadingsVal($name,".".$reading."_max", 0))
		{
			$return = undef;
		}
		else
		{
			$return = "Value not allowed! Possible Values must be between: ".$min." and ".ReadingsVal($name,".".$reading."_max", 0);
		}
	}
	elsif ((my $possibleValues = ReadingsVal($name,".".$reading."_possibleValues", "ERR")) ne "ERR")
	{
		#Log3 $name, 4, "$name -> Check for array for ".$reading.":".$val;
		$return = "Value not allowed! Possible Values: ".$possibleValues;
		#Log3 $name, 4, "$name -> Check for array possible values:".$possibleValues;
		
		my @possibleValues = split('; ',$possibleValues);
		
		foreach my $tmp (@possibleValues){
			$return = undef if ($val == $tmp);
		}
	}
	
	return $return;
}


###############################################################
#                  SMAEVCharger getCurlcmd
###############################################################
sub SMAEVCharger_getCurlcmd($$;$)
{
	# get the curlcmd infos for the api call
	my ($hash, $api, $data) = @_;
	
	# get all basic infos for the curl command
	my $baseurl = $hash->{HELPER}{BASEURL};
	my $curlcmd = "";
	my $url = "";
	my $special_header = "";
	my $cmd_call = "curl -i -s -k -X ";
	my $method = "'POST' ";
	my $header = "-H 'Host: $hash->{HOST}' -H 'Connection: close' -H 'Accept: application/json, text/plain, */*' -H 'User-Agent: okhttp/3.10.0' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Dest: empty' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' ";
	my $cookies = "-b '$hash->{HELPER}{SESSIONID}' ";
	my $token = "-H 'Authorization: Bearer $hash->{HELPER}{ACCESS_TOKEN}' " if (defined($hash->{HELPER}{ACCESS_TOKEN}));
	my $len_corr = 0; # maybe there are chars in data which should not be count for header content_len

	Log3 $hash->{NAME}, 5, "$hash->{NAME} -> SMAEVCgarger_getCurlcmd";
	
	#correct string len with count of masking char \
	if (defined ($data))
	{
		$len_corr = () = $data =~ /\\/g;
	}
	
	# check wich command we have to build
	if ($api eq "login")
	{
		$url = $baseurl."/api/v1/token";
		my $content_len = length($data) - $len_corr;
		$data = "--data-binary '$data' ";
		$special_header = "-H 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' -H 'Content-Length: $content_len' -H 'Origin: $baseurl' -H 'Referer: $baseurl/webui/login' ";
		$cookies = "";
		$token = "";
	}
	elsif ($api eq "refresh_token")
	{
		my $refresh_token = $hash->{HELPER}{REFRESH_TOKEN};
		$url = $baseurl."/api/v1/token";
		$data = "grant_type=refresh_token&refresh_token=$refresh_token ";
		my $content_len = length($data);
		$data = " --data-binary '$data' ";
		$special_header = "-H 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' -H 'Content-Length: $content_len' -H 'Origin: $baseurl' -H 'Referer: $baseurl/webui/login' ";
	}
	elsif ($api eq "livedata")
	{
		$url = $baseurl.'/api/v1/measurements/live/';
		$data = '[{"componentId":"IGULD:SELF"}]'; # cmd to get live data from wallbox
		my $content_len = length($data);
		$data = "--data-binary '$data' ";
		$special_header = "-H 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' -H 'Content-Length: $content_len' -H 'Referer: $baseurl/webui/login' ";
	}
	elsif ($api eq "read_params")
	{
		$url = $baseurl.'/api/v1/parameters/search/';
		my $content_len = length($data) - $len_corr;
		$data = "--data-binary '$data' ";
		$special_header = "-H 'Content-Type: application/json' -H 'Content-Length: $content_len' -H 'Referer: $baseurl/webui/Plant:1,IGULD:SELF/configuration/view-parameters' ";
	}
	elsif ($api eq "write_params")
	{
		$url = $baseurl.'/api/v1/parameters/IGULD:SELF';
		my $content_len = length($data);
		$data = "--data-binary '$data' ";
		$special_header = "-H 'Content-Type: application/json' -H 'Content-Length: $content_len' -H 'Referer: $baseurl/webui/Plant:1,IGULD:SELF/configuration/view-parameters' ";
		$method = "'PUT' ";
		
		#my $curlcmd = "curl -i -s -k -X 'PUT' -H 'Host: $host' -H 'Connection: close' -H 'Content-Length: $content_len' -H 'Accept: application/json, text/plain, */*' -H 'Authorization: Bearer $access_token' -H 'User-Agent: okhttp/3.10.0' -H 'Content-Type: application/json' -H 'Origin: $baseurl' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Dest: empty' -H 'Referer: $baseurl/webui/Plant:1,IGULD:SELF/configuration/view-parameters' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' -b 'JSESSIONID=$cookies' --data-binary '$data' '$baseurl/api/v1/parameters/IGULD:SELF'";
	}
	elsif ($api eq "easyget")
	{
		$url = $baseurl.'/api/v1/plants/Plant:1';
		$special_header = "-H 'Referer: $baseurl/webui/Plant:1/dashboard' ";
		$method = "'GET' ";
		$data = " ";
	}
	else
	{
		$cmd_call = "";
	}
	
	if ($cmd_call ne "")
	{
		$curlcmd = $cmd_call.$method.$header.$special_header.$token.$cookies.$data.$url;
	}
	else
	{
		$curlcmd = "";
	}
	
	return $curlcmd;
}


###############################################################
#                  SMAEVCharger Initialize
###############################################################
sub SMAEVCharger_Initialize($)
{
	my ($hash) = @_;

	$hash->{DefFn}     = "SMAEVCharger_Define";
	$hash->{UndefFn}   = "SMAEVCharger_Undef";
	$hash->{GetFn}     = "SMAEVCharger_Get";
	$hash->{SetFn}     = "SMAEVCharger_Set";
	$hash->{AttrList}  = "interval " .
						"disable:1,0 " .
						"detail-level:0,1,2 " .
						"setting-level:0,1,2 " .
						$readingFnAttributes; 
	$hash->{AttrFn}    = "SMAEVCharger_Attr";

	return;
}

###############################################################
#                  SMAEVCharger Define
###############################################################
sub SMAEVCharger_Define($$) 
{
	my ($hash, $def) = @_;
	my @a = split("[ \t][ \t]*", $def);

	return "Error: Perl module ".$MissModulDateTime." is missing.
        Install it on Debian with: sudo apt-get install libdatetime-perl" if($MissModulDateTime);

	return "Wrong syntax: use define <name> SMAEVCharger <inv-hostname/inv-ip> <inv-username> <inv-userpwd> " if ((int(@a) < 5) and (int(@a) > 6));

	my $name                       	= $hash->{NAME};
	$hash->{LASTUPDATE}            	= 0;
	$hash->{INTERVAL}              	= $hash->{HELPER}{INTERVAL} = AttrVal($name, "interval", 60);
	$hash->{HELPER}{SESSIONID} 		= "";
	$hash->{HELPER}{ACCESS_TOKEN} 	= "";
	$hash->{HELPER}{REFRESH_TOKEN} 	= "";
	$hash->{HELPER}{EXPIRE_TOKEN} 	= 0;
	
	my ($Host);
	 
	my $User = $a[3];
	my $Pass = $a[4];      #todo evtl. verschlüsseln und mit set befehl änderbar machen?
	
	my $username = SMAEVCharger_SMAencrypt($User);
    my $password = SMAEVCharger_SMAencrypt($Pass);

	# extract IP or Hostname from $a[4]
	if (!defined $Host) 
	{
		#if ( $a[2] =~ /^([A-Za-z0-9_.])/ ) 
		# Test if IP
		if ($a[2] =~ /^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/)
		{
			 $Host = $a[2];
			 
			 # extract protocol if in definition
			 my ($protocoll, $ip) = $Host =~m/(https:\/\/)(.*)/;
			 if($protocoll){ $Host = $ip; };
			 
			 $hash->{HELPER}{BASEURL} = "https://".$Host;
		}
	} 
	 
	if (!defined $Host) 
	{
		return "Argument:{$a[2]} not accepted as Host or IP. Read device specific help file.";
	}
	
	$hash->{DEF} = "$Host $username $password";
	$hash->{USER} = $username;
	$hash->{PASS} = $password;
	$hash->{HOST} = $Host;

	InternalTimer(gettimeofday()+5, "SMAEVCharger_GetData", $hash, 0);      # Start Hauptroutine

	return undef;
}

###############################################################
#                  SMAEVCharger Undefine
###############################################################
sub SMAEVCharger_Undef($$) 
{
	my ($hash, $name) = @_;
	RemoveInternalTimer($hash);
	BlockingKill($hash->{HELPER}{RUNNING_PID});
	return undef;
}

###############################################################
#                  SMAEVCharger Get
###############################################################
sub SMAEVCharger_Get($$) 
{
	my ($hash, @a) = @_;
	return "\"get X\" needs at least an argument" if ( @a < 2 );
	my $name = shift @a;
	my $opt  = shift @a;
 
	my  $getlist = "Unknown argument $opt, choose one of ".
                "data:noArg showAccount:noArg";

	return "module is disabled" if(IsDisabled($name));

	if ($opt eq "data") 
	{
		SMAEVCharger_GetData($hash);
	}
	elsif( $opt eq 'showAccount' )
    {
      my $username = $hash->{USER};
      my $password = $hash->{PASS};

      return 'no username set' if( !$username );
      return 'no password set' if( !$password );

      $username = SMAEVCharger_SMAdecrypt( $username );
      $password = SMAEVCharger_SMAdecrypt( $password );

      return "username: $username\npassword: $password";
    }	
	else 
	{
		return "$getlist";
	}
	return undef;
}

###############################################################
#                  SMAEVCharger Set
###############################################################

sub SMAEVCharger_Set($$@) 
{
	my ($hash, $name, $cmd, $val) = @_;
	return "\"set $name\" needs at least one argument" unless(defined($cmd));
	my $resultStr = "";
	my @cList;
	my $setting_level = AttrVal($name, "setting-level", 0);

	push(@cList, " "); 
	
	foreach my $key (keys(%update_readings))
	{
		if( $update_readings{$key}{level} <= $setting_level )
		{
			push(@cList, $key.$update_readings{$key}{values});
		}
	}
	
	my $return = "Unknown argument $cmd, choose one of " . join(" ", @cList);
   
	return $return if $cmd eq '?';
   
	if(join(" ", @cList) =~ m/$cmd/) 
	{
		Log3 $name, 5, "$name - Set command exists:".$cmd;
		
		$return = SMAEVCharger_SMAcmd($hash, $cmd, $val);
	}
		   
	return $return;	
}


###############################################################
#                  SMAEVCharger Attr
###############################################################
sub SMAEVCharger_Attr(@) 
{
	my ($cmd,$name,$aName,$aVal) = @_;
    # $cmd can be "del" or "set"
    # $name is device name
    # aName and aVal are Attribute name and value
    my $hash = $defs{$name};
    my $do;

	if ($aName eq "disable") 
	{
        if($cmd eq "set") 
		{
            $do = ($aVal) ? 1 : 0;
        }
        $do = 0 if($cmd eq "del");
        my $val   = ($do == 1 ?  "disabled" : "initialized");

        readingsSingleUpdate($hash, "state", $val, 1);

        if ($do == 0) 
		{
            RemoveInternalTimer($hash);
            InternalTimer(time+5, 'SMAEVCharger_GetData', $hash, 0);
        } 
		else 
		{
            RemoveInternalTimer($hash);
        }
    }
	
	if ($aName eq "detail-level") {
		if ($cmd eq "set" and AttrVal($name,"setting-level", 0) > $aVal)
		{
			
			return "ERROR: first set setting-level because detail-level must be >= setting-level";
		}
		else
		{
			delete $defs{$name}{READINGS};
			RemoveInternalTimer($hash);
            InternalTimer(time+5, 'SMAEVCharger_GetData', $hash, 0);
		}
    }
	
	if ($aName eq "setting-level") {
        
		if ($cmd eq "set" and AttrVal($name,"detail-level", 0) < $aVal)
		{
			return "ERROR: for higher setting-level attribute detail-level must have same or higher level";
		}
		else
		{
			delete $defs{$name}{READINGS};
			RemoveInternalTimer($hash);
            InternalTimer(time+5, 'SMAEVCharger_GetData', $hash, 0);
		}
    }


    if ($aName eq "interval") 
	{
        if ($cmd eq "set") 
		{
            $hash->{HELPER}{INTERVAL} = $aVal;
			$hash->{INTERVAL} = $aVal;
            Log3 $name, 3, "$name - Set $aName to $aVal";
        } else 
		{
            $hash->{INTERVAL} = $hash->{HELPER}{INTERVAL} = 60;
        }
    }

	
	return;
}

###############################################################
#                  Main Loop - Get Data from EV Charger
###############################################################
sub SMAEVCharger_GetData($)
{
	my ($hash) = @_;
	my $name = $hash->{NAME};
	my $interval = AttrVal($name, "interval", 60);
	 
	RemoveInternalTimer($hash, "SMAEVCharger_GetData");

	if ($init_done != 1) 
	{
		InternalTimer(gettimeofday()+5, "SMAEVCharger_GetData", $hash, 0);
		return;
	}

	return if(IsDisabled($name));
	 
	if (exists($hash->{HELPER}{RUNNING_PID})) 
	{
		Log3 ($name, 4, "SMAEVCharger $name - WARNING - old process $hash->{HELPER}{RUNNING_PID}{pid} will be killed now to start a new BlockingCall");
		BlockingKill($hash->{HELPER}{RUNNING_PID});
	}

	Log3 ($name, 3, "$name - ##########  SMAEVCharger get all data  ##########");

	# do operation
	InternalTimer(gettimeofday()+$interval, "SMAEVCharger_GetData", $hash, 0);

	$hash->{HELPER}{RUNNING_PID} = BlockingCall("SMAEVCharger_Run", "$name", "SMAEVCharger_Done", 60, "SMAEVCharger_Aborted", $hash);
	$hash->{HELPER}{RUNNING_PID}{loglevel} = 4;

	return;
}

###############################################################
#          non-blocking EVCharger data transfer
###############################################################
sub SMAEVCharger_Run($) 
{
	my ($name)   = @_;
	my $hash     = $defs{$name};
	my $interval = AttrVal($name, "interval", 60);
	my $response = "";
	my $code = 0;
	my $ret = 0;

	Log3 ($name, 4, "$name -> Start BlockingCall SMAEVCharger_Run");

	# login to EV Charger
	if(SMAEVCharger_SMAlogon($hash->{HOST}, SMAEVCharger_SMAdecrypt($hash->{PASS}),SMAEVCharger_SMAdecrypt($hash->{USER}), $hash))
	{
		Log3 $name, 4, "$name - login succes / start getting live data";
		
		my $baseurl = $hash->{HELPER}{BASEURL};
		my $host = $hash->{HOST};
		my $cookies = $hash->{HELPER}{SESSIONID};
		my $access_token = $hash->{HELPER}{ACCESS_TOKEN};
		my $url = $baseurl.'/api/v1/measurements/live/';
		my $data = '\'[{"componentId":"IGULD:SELF"}]\''; # cmd to get live data from wallbox
		
		my $curlcmd = SMAEVCharger_getCurlcmd($hash, "livedata");
		Log3 $name, 5, "$name - Curl cmd livedata: ".$curlcmd;

		$response = `$curlcmd`;
		my ($head,$body) = split( m{\r?\n\r?\n}, $response,2 );
		($code) = $head =~m{\A\S+ (\d+)};
			
		if($code == 200) # all ok for live data
		{
			Log3 $name, 5, "$name - Actual Live Data: ".$body;
			$response = $body;
			$ret = 1;
			
			#if live data is ok we should also get param data
			
			$url = $baseurl.'/api/v1/parameters/search/';
			$data = '{"queryItems":[{"componentId":"IGULD:SELF"}]}'; # cmd to get params
			$access_token = $hash->{HELPER}{ACCESS_TOKEN};
			
			$curlcmd = SMAEVCharger_getCurlcmd($hash, "read_params", $data);
				
			Log3 $name, 5, "$name - Curl cmd to read param: ".$curlcmd;

			my $response_param = `$curlcmd`;
			my ($head,$body) = split( m{\r?\n\r?\n}, $response_param,2 );
			($code) = $head =~m{\A\S+ (\d+)};
			
			if($code == 200) # all ok for param data
			{
				Log3 $name, 5, "$name - Parameter: ".$body;
				$response = $response.'|'.$body;
			}
			else
			{
				Log3 $name, 3, "$name - Parameter Error: ".$code;
				$response = $response.'|[{"componentId":"ERR"}]';
				
				Log3 $name, 5, "$name Response in Error: ".$response;
			}
		}
		else
		{
			#todo err handling
			Log3 $name, 3, "$name - Actual Live Data Error: ".$code;
			$response = "Error: Get Data with code:".$code;
			$ret = 0;
		}
	}
	else 
	{
		Log3 $name, 3, "$name - Login failed";
		$response = "Error: Login with code:".$code;
		$ret = 0;
	}

	# all data received
	#SMAEVCharger_SMAlogout($hash,$hash->{HOST});
	
	# store session info for blocking call parent
	my $session_info = encode_base64($hash->{HELPER}{SESSIONID}."|".$hash->{HELPER}{ACCESS_TOKEN}."|".$hash->{HELPER}{REFRESH_TOKEN}."|".$hash->{HELPER}{EXPIRE_TOKEN},"");
	 
	$response = encode_base64($response,"");

	Log3 ($name, 4, "$name -> BlockingCall SMAEVCharger_Run finished");
	  
	return "$name|$ret|$session_info|$response";
}

###############################################################
# 	Helper to change readings into user readable names 
###############################################################
sub SMAEVCharger_handledata($$$)
{
	my ($hash, $data, $param) = @_;
	my $name = $hash->{NAME};
	
	# Get the current detail-level attribute
     my $detail_level  = AttrVal($name, "detail-level", 0);
	
	my 	$livedata->{"Measurement.ChaSess.WhIn"} = "Energie_Ladevorgang"; 							# in Wh
		$livedata->{"Measurement.Chrg.ModSw"} = "Schalterstellung_Drehschalter";
		$livedata->{"Measurement.GridMs.A.phsA"} = "Netzstrom_Phase_L1";
		$livedata->{"Measurement.GridMs.A.phsB"} = "Netzstrom_Phase_L2";
		$livedata->{"Measurement.GridMs.A.phsC"} = "Netzstrom_Phase_L3";
		$livedata->{"Measurement.GridMs.PhV.phsA"} = "Netzspannung_Phase_L1";
		$livedata->{"Measurement.GridMs.PhV.phsB"} = "Netzspannung_Phase_L2";
		$livedata->{"Measurement.GridMs.PhV.phsC"} = "Netzspannung_Phase_L3";
		$livedata->{"Measurement.Metering.GridMs.TotWIn"} = "Leistung_Bezug"; 						# in W
		$livedata->{"Measurement.Metering.GridMs.TotWIn.ChaSta"} = "Leistung_Ladestation"; 			# in W
		$livedata->{"Measurement.Metering.GridMs.TotWhIn"} = "Zaehlerstand_Bezugszaehler"; 			# in Wh 
		$livedata->{"Measurement.Metering.GridMs.TotWhIn.ChaSta"} = "Zaehlerstand_Ladestation"; 	#in Wh
		$livedata->{"Measurement.Operation.EVeh.ChaStt"} = "Status_Ladevorgang"; 					# 200111 -> nicht verbunden, 200112 -> verbunden 200113 -> wird geladen
		$livedata->{"Measurement.Operation.EVeh.Health"} = "Status_verbundenes_Fahrzeug"; 			# 307 -> "Ok"
		$livedata->{"Measurement.Operation.Evt.Msg"} = "Status_Meldung"; 							# 302 -> "ok" ?
		$livedata->{"Measurement.Operation.Health"} = "Status_Zustand"; 							# 307 -> "Ok"
		$livedata->{"Setpoint.PlantControl.Inverter.FstStop"} = "Schnellabschaltung"; 				# 1467 -> "Start"
		
	# advanced infos
	if ($detail_level > 0)
	{
		$livedata->{"Measurement.GridMs.Hz"} = "Netzfrequenz";
		$livedata->{"Measurement.GridMs.TotPF"} = "Verschiebungsfaktor";
		$livedata->{"Measurement.GridMs.TotVA"} = "Scheinleistung";
		$livedata->{"Measurement.GridMs.TotVAr"} = "Blindleistung";
		$livedata->{"Measurement.Wl.AcqStt"} = "Status_WLAN_Scan";
		$livedata->{"Measurement.Wl.ConnStt"} = "Status_WLAN_Verbindung"; 							# 1725 -> keine Verbindung
		$livedata->{"Measurement.Wl.SigPwr"} = "Signalstaerke_Netzwerk"; 
	}
	
	# expert infos
	if ($detail_level > 1)
	{
		$livedata->{"Measurement.InOut.GI1"} = "digitaler_Gruppeneingang";
		$livedata->{"Measurement.Operation.WMaxLimSrc"} = "Digitaler_Eingang"; 						# eigentlich uninteressant
		$livedata->{"Measurement.Wl.SoftAcsConnStt"} = "Status_Soft_Access_Point"; 					# 308 -> "Ein"
	}
	
	my $readings = {	"Measurement.ChaSess.WhIn" => "Energie_Ladevorgang", # in Wh
					"Measurement.GridMs.A.phsA" => "Netzstrom_Phase_L1",
					"Measurement.GridMs.A.phsB" => "Netzstrom_Phase_L2",
					"Measurement.GridMs.A.phsC" => "Netzstrom_Phase_L3",
   					"Measurement.GridMs.Hz" => "Netzfrequenz",
					"Measurement.GridMs.PhV.phsA" => "Netzspannung_Phase_L1",
					"Measurement.GridMs.PhV.phsB" => "Netzspannung_Phase_L2",
					"Measurement.GridMs.PhV.phsC" => "Netzspannung_Phase_L3",
					"Measurement.GridMs.TotPF" => "Verschiebungsfaktor",
					"Measurement.GridMs.TotVA" => "Scheinleistung",
					"Measurement.GridMs.TotVAr" => "Blindleistung",
   					"Measurement.InOut.GI1" => "digitaler_Gruppeneingang",
					"Measurement.Metering.GridMs.TotWIn" => "Leistung_Bezug", # in W
					"Measurement.Metering.GridMs.TotWIn.ChaSta" => "Leistung_Ladestation", # in W
					"Measurement.Metering.GridMs.TotWhIn" => "Zaehlerstand_Bezugszaehler", # in Wh 
					"Measurement.Metering.GridMs.TotWhIn.ChaSta" => "Zaehlerstand_Ladestation", #in Wh
					"Measurement.Operation.EVeh.ChaStt" => "Status_Ladevorgang", # 200111 -> nicht verbunden, 200112 -> verbunden 200113 -> wird geladen
					"Measurement.Operation.EVeh.Health" => "Status_verbundenes_Fahrzeug", # 307 -> "Ok"
					"Measurement.Operation.Evt.Msg" => "Status_Meldung", # 302 -> "ok" ?
					"Measurement.Operation.Health" => "Status_Zustand", # 307 -> "Ok"
					"Measurement.Operation.WMaxLimSrc" => "Digitaler_Eingang", # eigentlich uninteressant
					"Measurement.Wl.AcqStt" => "Status_WLAN_Scan",
					"Measurement.Wl.ConnStt" => "Status_WLAN_Verbindung", # 1725 -> keine Verbindung
					"Measurement.Wl.SigPwr" => "Signalstaerke_Netzwerk", 
					"Measurement.Wl.SoftAcsConnStt" => "Status_Soft_Access_Point", # 308 -> "Ein"
					"Setpoint.PlantControl.Inverter.FstStop" => "Schnellabschaltung" # 1467 -> "Start"
				};
				
	# basic params
	my 	$params->{"Parameter.Chrg.ActChaMod"} = "Param_Betriebsart_Ladevorgang";
		$params->{"Parameter.Chrg.AMinCha"} = "Param_Minimaler_Ladestrom";
		$params->{"Parameter.Chrg.Plan.DurTmm"} = "Param_Dauer_Ladevorgang";
		$params->{"Parameter.Chrg.Plan.En"} = "Param_Energiemenge_Ladevorgang";
		$params->{"Parameter.Chrg.Plan.StopTm"} = "Param_Ende_Ladevorgang";
		$params->{"Parameter.Chrg.StpWhenFl"} = "Param_Trennung_nach_Vollladung";
		$params->{"Parameter.Chrg.StpWhenFlTm"} = "Param_Ladebereitschaft_bis_Trennung";
		$params->{"Parameter.GridGuard.Cntry.VRtg"} = "Param_Netz_Nennspannung";
		$params->{"Parameter.PCC.ARtg"} = "Param_Nennstrom_Netzanschluss";
		$params->{"Parameter.PCC.FlbInv.WMax"} = "Param_Fallback_Wirkleistungsbegrenzung";
		$params->{"Parameter.Chrg.ChrgApv"} = "Param_Manuelle_Ladefreigabe";
		$params->{"Parameter.Chrg.ChrgLok"} = "Param_Ladefreigabe_ueber_App";
		$params->{"Parameter.Inverter.AcALim"} = "Param_AC_Strom_Begrenzung";
		

		
	# advanced params
	if ($detail_level > 0)
	{
		$params->{"Parameter.Chrg.MinSwTms"} = "Param_Minimale_Schaltdauer_Relais";
		$params->{"Parameter.Chrg.UseEnergyMeter"} = "Param_Betrieb_mit_Netzanschlusspunktzaehler";
		$params->{"Parameter.Inverter.WMax"} = "Param_Nennwirkleistung_WMaxOut";
		$params->{"Parameter.Inverter.WMaxIn"} = "Param_Nennwirkleistung_WMaxIn";
		$params->{"Parameter.Inverter.WMaxInRtg"} = "Param_Bemessungswirkleistung_WMaxInRtg";
		$params->{"Parameter.Nameplate.ARtg"} = "Param_Nennstrom_alle_Phasen";
		$params->{"Parameter.Nameplate.Location"} = "Param_Geraetename";
		$params->{"Parameter.PCC.WMaxAsym"} = "Param_Maximale_Schieflast";
		
	}
	
	# expert params
	if ($detail_level > 1)
	{
		$params->{"Parameter.Spdwr.IgmpQryTms"} = "Param_IGMP_Query_Intervall";
		$params->{"Parameter.Spdwr.IgmpQryTx"} = "Param_IGMP_Anfragen_senden";
		$params->{"Parameter.Upd.AutoUpdIsOn"} = "Param_Auto_Update_an";
		$params->{"Parameter.DevUpd.IsOn"} = "Param_Geraete_Update_ein";
		$params->{"Parameter.Inverter.OutPhs"} = "Param_Phasenzuordnung";
		$params->{"Parameter.Nameplate.ChrgCtrl.ChrgTypTxt"} = "Param_Typ_Ladecontroller";
		$params->{"Parameter.Nameplate.ChrgCtrl.SerNumTxt"} = "Param_Seriennummer_Ladecontrollers";
		$params->{"Parameter.Nameplate.ChrgCtrl.SusyId"} = "Param_SusyID_Ladecontrollers";
		$params->{"Parameter.Nameplate.ChrgCtrl.SwRevTxt"} = "Param_SWVersion_Ladecontroller";
		$params->{"Parameter.Nameplate.CmpMain.HwRev"} = "Param_HWVersion_Hauptprozessor";
		$params->{"Parameter.Nameplate.CmpMain.Rev"} = "Param_Umbaustand_Hauptprozessor";
		$params->{"Parameter.Nameplate.CmpMain.SerNum"} = "Param_Seriennummer_Hauptprozessor";
		$params->{"Parameter.Nameplate.CmpMain.SusyId"} = "Param_SUSyID_Hauptprozessor";
		$params->{"Parameter.Nameplate.CmpOS.SwRev"} = "Param_Firmware_Version_Betriebssystem";
		$params->{"Parameter.Nameplate.MacId"} = "Param_MAC-Adresse";
		$params->{"Parameter.Nameplate.MainModel"} = "Param_Geraeteklasse";
		$params->{"Parameter.Nameplate.Model"} = "Param_Geraetetyp";
		$params->{"Parameter.Nameplate.ModelStr"} = "Param_Typenbezeichnung";
		$params->{"Parameter.Nameplate.PkgRev"} = "Param_Softwarepaket";
		$params->{"Parameter.Nameplate.SerNum"} = "Param_Seriennummer";
		$params->{"Parameter.Nameplate.Vendor"} = "Param_Hersteller";
		$params->{"Parameter.Nameplate.WlMacId"} = "Param_WLAN_MAC";
		$params->{"Parameter.Operation.ComTmOut"} = "Param_Timeout_nach_Kommunikationsverlust";
		$params->{"Parameter.Spdwr.ActlDnsSrvIp"} = "Param_Akt_Speedwire_Serveradresse";
		$params->{"Parameter.Spdwr.ActlGwIp"} = "Param_Akt_Speedwire_Gateway";
		$params->{"Parameter.Spdwr.ActlIp"} = "Param_Akt_Speedwire_IP";
		$params->{"Parameter.Spdwr.ActlSnetMsk"} = "Param_Akt_Speedwire_Subnetzmaske";
		$params->{"Parameter.Spdwr.AutoCfgIsOn"} = "Automatische_Speedwire-Konfig_an";
		$params->{"Parameter.SwCmp.CmpEnnexOS.Frwk.SwRev"} = "Param_ennexOS_Framework_Version";
		$params->{"Parameter.Sys.DevRstr"} = "Param_Geraeteneustart_ausloesen";
		$params->{"Parameter.Upd.AvalChkIstl"} = "Param_Auto_Speedwire_Konfig_an";
		$params->{"Parameter.Wl.ActlDnsSrvIp"} = "Aktuelle_Speedwire-DNS-Serveradresse";
		$params->{"Parameter.Wl.ActlGwIp"} = "Param_IP_Gateway_WLAN";
		$params->{"Parameter.Wl.ActlIp"} = "Param_IP_WLAN";
		$params->{"Parameter.Wl.ActlSnetMsk"} = "Param_IP_Subnetz_WLAN";
		$params->{"Parameter.Wl.AutoCfgIsOn"} = "Param_Auto_Update_an";
		$params->{"Parameter.Wl.DoAcq"} = "Param_WLAN_suchen";
		$params->{"Parameter.Wl.DoWPS"} = "Param_WPS_aktivieren";
		$params->{"Parameter.Wl.ExsNetw[]"} = "Param_Gefundenes_WLAN";
		$params->{"Parameter.Wl.IsOn"} = "Param_WLAN_eingeschaltet";
		$params->{"Parameter.Wl.Sec.Cry"} = "Param_Verschluesselung_WLAN";
		$params->{"Parameter.Wl.Sec.Psk"} = "Param_WLAN-Passwort";
		$params->{"Parameter.Wl.Sec.Ssid"} = "Param_SSID_WLAN";
		$params->{"Parameter.Wl.SoftAcsIsOn"} = "Param_Soft_Access_Point_an";
	}
	
				
	# Update Live Data Readings
	my $json = decode_json( $data );
   
	foreach my $item ( @$json )
	{
		my $val = SMAEVCharger_getReadableCode($item->{"values"}->[0]->{"value"});
		
		#old readingsBulkUpdate($hash, $readings->{$item->{"channelId"}} , $val);
		readingsBulkUpdate($hash, $livedata->{$item->{"channelId"}} , $val);
		
		if(defined($livedata->{$item->{"channelId"}}))
		{
			Log3 $name, 5, "$name - Livedata:".$item->{"channelId"}." Reading:".$livedata->{$item->{"channelId"}}." Wert:".$val;
		}
	  
		#Log3 $name, 5, "$name - Readings Update:".$item->{"channelId"}." Reading:".$readings->{$item->{"channelId"}}." Wert:".$val;
	}
	
	Log3 $name, 4, "$name - Loop Readings update done";
   
	# Update Param Readings
	$json = decode_json( $param );
   
	# only if param is from the charger
	if ($json->[0]->{"componentId"} eq "IGULD:SELF")
	{
		$json = $json->[0]->{values};

		foreach my $item ( @$json )
		{
			if(defined($item->{"channelId"}))
			{
				#read possible values:
				if(defined($item->{"min"}))
				{
					# save as non visible reading
					Log3 $name, 4, "$name - Readings Update possible Values: min=".$item->{"min"}." max=".$item->{"max"};
					if(defined($params->{$item->{"channelId"}}))
					{
						readingsBulkUpdate($hash, ".".$params->{$item->{"channelId"}}."_min" , $item->{"min"});
						readingsBulkUpdate($hash, ".".$params->{$item->{"channelId"}}."_max" , $item->{"max"});
					}
				}
				
				if(defined($item->{"possibleValues"}))
				{
					# save as non visible reading
					
					Log3 $name, 4, "$name - Readings Update possible Values:".join("; ",@{$item->{"possibleValues"}});
					if(defined($params->{$item->{"channelId"}}))
					{
						readingsBulkUpdate($hash, ".".$params->{$item->{"channelId"}}."_possibleValues" , join("; ",@{$item->{"possibleValues"}}));
					}
				}
			
				if ($item->{"channelId"} eq "Parameter.Chrg.Plan.StopTm")
				{
					my $time = FmtDateTime($item->{"value"});
					readingsBulkUpdate($hash, $params->{$item->{"channelId"}} , $time);
				}
				else
				{
					my $val = SMAEVCharger_getReadableCode($item->{"value"});
					readingsBulkUpdate($hash, $params->{$item->{"channelId"}} , $val);
				}
				
				if(defined($params->{$item->{"channelId"}}))
				{
					Log3 $name, 5, "$name - Readings Update:".$item->{"channelId"}.' Reading:'.$params->{$item->{"channelId"}}.' Wert:'.$item->{"value"};
				}
			}
		}
		
		Log3 $name, 4, "$name - Loop Params update done";
		
		#calculate additional readings
		SMAEVCharger_CalculateReadings($hash);
	}
   
   return;
}


###############################################################
#   Calculate Specials Readings which are not in Charger
###############################################################
sub SMAEVCharger_CalculateReadings ($) 
{
	my ($hash) = @_;
	my $name = $hash->{NAME};
	
	
	# Remember last plugin time
	if($hash->{HELPER}{Status_Ladevorgang} eq "nicht verbunden" and ReadingsVal($name, "Status_Ladevorgang", "nicht verbunden") ne "nicht verbunden")
	{
		readingsBulkUpdate($hash, "Startzeit_Verbindung" , TimeNow());
		readingsBulkUpdate($hash, "Anzahl_Ladevorgaenge" , 0);
	}	
	elsif(ReadingsVal($name, "Status_Ladevorgang", "nicht verbunden") eq "nicht verbunden")
	{
		readingsBulkUpdate($hash, "Startzeit_Verbindung" , "nicht verbunden");
	}
	
	# count charges since last plugin time, will be shown until next plugin
	if($hash->{HELPER}{Status_Ladevorgang} eq "verbunden" and ReadingsVal($name, "Status_Ladevorgang", "") eq "Ladevorgang aktiv")
	{
		readingsBulkUpdate($hash, "Anzahl_Ladevorgaenge" , ReadingsNum($name, "Anzahl_Ladevorgaenge", "") + 1);
	}
}


###############################################################
#         Auswertung non-blocking Charger Datenabruf
###############################################################
sub SMAEVCharger_Done ($) 
{
	my ($string) = @_;
	return unless defined $string; 
	
	my ($name, $success, $session_info, $data) = split("\\|", $string);
	my $hash     = $defs{$name};

	Log3 ($name, 4, "$name -> Start BlockingCall SMAEVCharger_Done");
	
	#save the actual session infos
	$session_info = decode_base64($session_info);
	($hash->{HELPER}{SESSIONID}, $hash->{HELPER}{ACCESS_TOKEN}, $hash->{HELPER}{REFRESH_TOKEN},$hash->{HELPER}{EXPIRE_TOKEN}) = split("\\|", $session_info);
	
	#remember old values for calculating extra readings
	$hash->{HELPER}{Status_Ladevorgang} = ReadingsVal($name, "Status_Ladevorgang", "nicht verbunden");
	
	
	
	readingsBeginUpdate($hash);

	if ($success == 1)
	{
		$data = decode_base64($data);
		my ($livedata, $param) = split("\\|", $data);
		
		# Get current time
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
		$hash->{LASTUPDATE} = sprintf "%02d.%02d.%04d / %02d:%02d:%02d" , $mday , $mon+=1 ,$year+=1900 , $hour , $min , $sec ;
		
		#$livedata = decode_base64($livedata);
		Log3 ($name, 5, "$name -> livedata after decoding:".$livedata);
		
		#$param = decode_base64($param);
		Log3 ($name, 5, "$name -> param after decoding:".$param);
		
		SMAEVCharger_handledata($hash, $livedata, $param);
		readingsBulkUpdate($hash, "state", "Data retrieved");
	}
	else
	{
		readingsBulkUpdate($hash, "state", "Error retrieving data");
		Log3 ($name, 3, "$name - Error retrieving data");
	}
	 
	readingsEndUpdate( $hash, 1 );
	 
	delete($hash->{HELPER}{RUNNING_PID});
	Log3 ($name, 4, "$name -> BlockingCall SMAEVCharger_Done finished");

	return;
}

###############################################################
#           Abbruchroutine Timeout Charger Abfrage
###############################################################
sub SMAEVCharger_Aborted(@) 
{
	my ($hash,$cause) = @_;
	my $name      = $hash->{NAME};
	$cause = $cause?$cause:"Timeout: process terminated";

	Log3 ($name, 1, "SMAEVCgarger $name -> BlockingCall $hash->{HELPER}{RUNNING_PID}{fn} $cause");
	readingsSingleUpdate($hash,"state",$cause, 1);

	delete($hash->{HELPER}{RUNNING_PID});

	return;
}

##########################################################################
#                     SMA Command Execution
##########################################################################
sub SMAEVCharger_SMAcmd($$$) {

	my ($hash, $cmd, $value) = @_;
	
	my $baseurl = $hash->{HELPER}{BASEURL};
	my $host = $hash->{HOST};
	my $cookies = $hash->{HELPER}{SESSIONID};
	my $access_token = $hash->{HELPER}{ACCESS_TOKEN};
	my $url = $baseurl.'/api/v1/measurements/live/';
	my $name = $hash->{NAME};
	my $return = undef;
	
	# Get the current setting-level attribute
     my $setting_level  = AttrVal($name, "setting-level", 0);
	
	my 	$params->{"Param_Betriebsart_Ladevorgang"} = "Parameter.Chrg.ActChaMod";
		$params->{"Param_Minimaler_Ladestrom"} = "Parameter.Chrg.AMinCha";
		$params->{"Param_Dauer_Ladevorgang"} = "Parameter.Chrg.Plan.DurTmm";
		$params->{"Param_Energiemenge_Ladevorgang"} = "Parameter.Chrg.Plan.En";
		$params->{"Param_Manuelle_Ladefreigabe"} = "Parameter.Chrg.ChrgApv";
		$params->{"Param_Ladefreigabe_ueber_App"} = "Parameter.Chrg.ChrgLok";
		
			
	# advanced params
	if ($setting_level > 0)
	{
		$params->{"Param_Minimale_Schaltdauer_Relais"} = "Parameter.Chrg.MinSwTms";
		$params->{"Param_Trennung_nach_Vollladung"} = "Parameter.Chrg.StpWhenFl";
		$params->{"Param_Ladebereitschaft_bis_Trennung"} = "Parameter.Chrg.StpWhenFlTm";
		$params->{"Param_Betrieb_mit_Netzanschlusspunktzaehler"} = "Parameter.Chrg.UseEnergyMeter";
		$params->{"Param_Nennstrom_Netzanschluss"} = "Parameter.PCC.ARtg";
		$params->{"Param_Nennwirkleistung_WMaxOut"} = "Parameter.Inverter.WMax";
		$params->{"Param_Nennwirkleistung_WMaxIn"} = "Parameter.Inverter.WMaxIn";
		$params->{"Param_AC_Strom_Begrenzung"} = "Parameter.Inverter.AcALim";
		$params->{"Param_Maximale_Schieflast"} = "Parameter.PCC.WMaxAsym";
		$params->{"Param_Fallback_Wirkleistungsbegrenzung"} = "Parameter.PCC.FlbInv.WMax";
	}
	
	# expert params
	if ($setting_level > 1)
	{
		$params->{"Param_Timeout_nach_Kommunikationsverlust"} = "Parameter.Operation.ComTmOut";
		$params->{"Param_IGMP_Query_Intervall"} = "Parameter.Spdwr.IgmpQryTms";
		$params->{"Param_Auto_Update_an"} = "Parameter.Upd.AutoUpdIsOn";
		$params->{"Param_Geraeteneustart_ausloesen"} = "Parameter.Sys.DevRstr";
		$params->{"Param_WLAN_suchen"} = "Parameter.Wl.DoAcq";
		$params->{"Param_WPS_aktivieren"} = "Parameter.Wl.DoWPS";
		$params->{"Param_WLAN_eingeschaltet"} = "Parameter.Wl.IsOn";
		$params->{"Param_Verschluesselung_WLAN"} = "Parameter.Wl.Sec.Cry";
		$params->{"Param_WLAN-Passwort"} = "Parameter.Wl.Sec.Psk";
		$params->{"Param_SSID_WLAN"} = "Parameter.Wl.Sec.Ssid";
		$params->{"Param_Soft_Access_Point_an"} = "Parameter.Wl.SoftAcsIsOn";
	}
			
	Log3 $name, 5, "$name - PUT Parameter: ".$cmd." : ".$value;
	
	if (defined($params->{$cmd}) 
		and SMAEVCharger_SMAlogon($hash->{HOST}, SMAEVCharger_SMAdecrypt($hash->{PASS}), SMAEVCharger_SMAdecrypt($hash->{USER}), $hash))
	{	
		my $timestamp = POSIX::strftime("%Y-%m-%dT%H:%M:%S.000Z",gmtime());
		
		if( $cmd eq "Param_Dauer_Ladevorgang" and $value =~ m/:/)
		{
			my ($hour, $min) = split(":",$value);
			$value = $hour * 60 + $min;
		}
		
		# if charging volume changes during predefined charging methode, set ending time correct
		my $add_update = "";
		if ( $cmd eq "Param_Energiemenge_Ladevorgang" and ReadingsVal($name, "Param_Betriebsart_Ladevorgang", "") eq "Laden_mit_Vorgabe")
		{
			my $charging_stop = time_str2num(ReadingsVal($name, "Param_Ende_Ladevorgang",""));
			$add_update = " ,{\"channelId\":\"Parameter.Chrg.Plan.StopTm\",\"timestamp\":\"$timestamp\",\"value\":$charging_stop}";
		}
		
		my $val = $value;
		
		if ( $reading_codes{$value} )
		{
			$val = $reading_codes{$value};
		}
		
		#check if value is in range
		if(! defined ($return = SMAEVCharger_checkPossibleValues($name, $cmd, $val)))
		{
			my $data = "{\"values\":[{\"channelId\":\"$params->{$cmd}\",\"timestamp\":\"$timestamp\",\"value\":\"$val\"}$add_update]}";
			my $content_len = length($data);
			
			Log3 $name, 4, "$name - PUT data: ".$data;
			
			
			my $curlcmd = SMAEVCharger_getCurlcmd($hash, "write_params",$data);
		
			Log3 $name, 5, "$name - PUT data: ".$curlcmd;
			
			my $response = `$curlcmd`;
			
			my ($head,$body) = split( m{\r?\n\r?\n}, $response,2 );
			my ($code) = $head =~m{\A\S+ (\d+)};
			
			Log3 $name, 4, "$name - PUT data response: ".$response;
			
			if ($code == 204)
			{
				readingsSingleUpdate($hash, $cmd, $value, 1);
				$return = undef;
			}
			else 
			{
				$return = "Error: Couldn't send Info to Charger";
			}
		}
	}
	else
	{
		$return = "Error: Couldn't send Info to Charger";
	}
	
	return $return;
}

##########################################################################
#                                Login
##########################################################################
sub SMAEVCharger_SMAlogon($$$$) 
{
	# Parameters: host - passcode
	my ($host,$pass, $user, $hash)  = @_;
	my $name                = $hash->{NAME};
	my ($cmd, $timestmp, $myID, $target_ID, $spkt_ID, $cmd_ID);

	Log3 $name, 4, "$name - Starting login or refresh token process ";

	#Login / SessionID / Token
	my $baseurl = "https://".$host;
	my $url = $baseurl."/api/v1/token";
	my $content_len=length($user.$pass)+39;
	my $data = 'grant_type=password&username='.$user.'&password='.$pass;
	
	# all things for handle the web calls
	my $curlcmd = "";
	my $response = "";
	my $head = "";
	my $body = "";
	my $code = 200;
	
	# for now using curl because in trouble to get certificate verification with httputils-calls?!
	# login call
	
	Log3 $name, 5, "$name - aktueller Token:".$hash->{HELPER}{ACCESS_TOKEN}.":" if (defined($hash->{HELPER}{ACCESS_TOKEN}));
	
	#first, look if we need to login
	if (defined($hash->{HELPER}{ACCESS_TOKEN}) and $hash->{HELPER}{ACCESS_TOKEN} ne "")
	{
		if	((time()+300) > $hash->{HELPER}{EXPIRE_TOKEN}) # token will be expired
		{
			Log3 $name, 4, "$name - check for refresh token ";
			
			$curlcmd = SMAEVCharger_getCurlcmd($hash, "refresh_token");
			
			Log3 $name, 5, "$name - Curlaufruf für refresh: ".$curlcmd;
			$response = `$curlcmd`;
			($head,$body) = split( m{\r?\n\r?\n}, $response,2 );
			($code) = $head =~m{\A\S+ (\d+)};
			
			if ($code == 200)
			{
				$hash->{HELPER}{ACCESS_TOKEN} = $body->{"access_token"};
				$hash->{HELPER}{REFRESH_TOKEN} = $body->{"refresh_token"}; 
				$hash->{HELPER}{EXPIRE_TOKEN} = time() + $body->{"expires_in"};
				
				Log3 $name, 5, "$name - new acess_token:".$hash->{HELPER}{ACCESS_TOKEN};
				Log3 $name, 5, "$name - new refresh_token:".$hash->{HELPER}{REFRESH_TOKEN};
				
				Log3 $name, 4, "$name - got new access token";
			}
		}
		else
		{
			# check if we need to login
			Log3 $name, 4, "$name - check for need of login ";
			$curlcmd = SMAEVCharger_getCurlcmd($hash, "easyget");
			
			Log3 $name, 5, "$name - Curlaufruf für get: ".$curlcmd;
			$response = `$curlcmd`;
			($head,$body) = split( m{\r?\n\r?\n}, $response,2 );
			($code) = $head =~m{\A\S+ (\d+)};
			
			Log3 $name, 5, "$name - Ergebnis easy_get: ".$response;
		}
	}
	else
	{
		$code = 401;
	}
	
	if ($code != 200) # we need to login
	{
		Log3 $name, 4, "$name - try login to $host with user $user and password $pass ";
		
		$curlcmd = SMAEVCharger_getCurlcmd($hash, "login", $data);

		Log3 $name, 5, "$name - Curlaufruf: ".$curlcmd;

		$response = `$curlcmd`;
		($head,$body) = split( m{\r?\n\r?\n}, $response,2 );
		($code) = $head =~m{\A\S+ (\d+)};
	 
		Log3 $name, 5, "$name - Curl Response Header: ".$head;
		Log3 $name, 5, "$name - Curl Response Body: ".$body;
		Log3 $name, 5, "$name - Curl Response Code: ".$code;
		
		if (defined $head && defined $body)
		{
			if ($code == 200) # login ok
			{
				my ($cookies) = $head =~m{JSESSIONID= ?(.*);};
				my ($sessionid, $othercookies) = split(/;/, $cookies,2);
				 
				Log3 $name, 5, "$name - Cookies:".$cookies;
				Log3 $name, 5, "$name - SessionID:".$sessionid;

				$body = decode_json($body);
				$hash->{HELPER}{ACCESS_TOKEN} = $body->{"access_token"};
				$hash->{HELPER}{REFRESH_TOKEN} = $body->{"refresh_token"}; 
				$hash->{HELPER}{EXPIRE_TOKEN} = time() + $body->{"expires_in"};
				 
				# remember all things for the actual session login
				$hash->{HELPER}{SESSIONID} = $sessionid;
				
				Log3 $name, 4, "$name - login success";
			}
			else
			{
				# todo err handling
				Log3 $name, 3, "$name - Curl Response Error Code:".$code.":";
				
				$hash->{HELPER}{SESSIONID} = "";
				$hash->{HELPER}{ACCESS_TOKEN} = "";
				$hash->{HELPER}{REFRESH_TOKEN} = ""; 
				$hash->{HELPER}{EXPIRE_TOKEN} = 0;
				
				return 0;
			}
		}
		else
		{
			Log3 $name, 3, "$name - Curl no header or body";
			
			$hash->{HELPER}{SESSIONID} = "";
			$hash->{HELPER}{ACCESS_TOKEN} = "";
			$hash->{HELPER}{REFRESH_TOKEN} = ""; 
			$hash->{HELPER}{EXPIRE_TOKEN} = 0;
			
			return 0;
		}
	}
	
	return 1;
}



##########################################################################
#                               Logout
##########################################################################
sub SMAEVCharger_SMAlogout($$) 
{
	# Parameters: host
	my ($hash,$host)   = @_;
	my $name           = $hash->{NAME};
 
 #todo

	return 1;
}

##########################################################################
#                            Encrypt Passwort/Username
##########################################################################

sub SMAEVCharger_SMAencrypt($)
{
  my ($decoded) = @_;
  my $key = getUniqueId();
  my $encoded;

  return $decoded if( $decoded =~ /crypt:/ );

  for my $char (split //, $decoded) {
    my $encode = chop($key);
    $encoded .= sprintf("%.2x",ord($char)^ord($encode));
    $key = $encode.$key;
  }

  return 'crypt:'.$encoded;
}

##########################################################################
#                            Decrypt Passwort/Username
##########################################################################

sub SMAEVCharger_SMAdecrypt($)
{
  my ($encoded) = @_;
  my $key = getUniqueId();
  my $decoded;

  return $encoded if( $encoded !~ /crypt:/ );
  
  $encoded = $1 if( $encoded =~ /crypt:(.*)/ );

  for my $char (map { pack('C', hex($_)) } ($encoded =~ /(..)/g)) {
    my $decode = chop($key);
    $decoded .= chr(ord($char)^ord($decode));
    $key = $decode.$key;
  }

  return $decoded;
}



1;

=pod
=item summary    Integration of SMA EVChargers over it's Speedwire (=Ethernet) Interface
=item summary_DE Integration von SMA Wallboxen über Speedwire (=Ethernet) Interface

=begin html

<a name="SMAEVCharger"></a>
<h3>SMAEVCharger</h3>

Module for the integration of a SMA EVCharger over it's Speedwire (=Ethernet) Interface.<br>
Tested on SMA EV Charger 22
<br><br>

<!--
Questions and discussions about this module you can find in the FHEM-Forum link:<br>
<a href="https://forum.fhem.de/index.php/topic,116543.msg1119664.html#msg1119664">SMA EV-Charger</a>.
<br><br>
-->

<b>Requirements</b>
<br><br>
This module requires:
<ul>
    <li>Perl Module: Date::Time        (apt-get install libdatetime-perl) </li>
	<li>Perl Module: Time::HiRes</li>
	<li>Perl Module: JSON</li>
	<li>FHEM Module: Blocking.pm</li>
</ul>
<br>
<br>


<b>Definition</b>
<ul>
<code>define &lt;name&gt; SMAEVCharger &lt;hostname/ip&gt; &lt;user&gt; &lt;password&gt;  </code><br>
<br>
<li>hostname/ip: IP-Adress of the charger, should be without protocol (for now hostname not testet!).</li>
<li>Example: define myWallbox 192.168.xxx.xxx username userpassword</li>
</ul>


<b>Operation method</b>
<ul>
The module logs on to the SMA Wallbox and reads live data (monitoring measurement values) as well as available parameters (configuration parameters). <br>
All values ​​that can be changed via the web interface can also be changed with the module. To reduce readings, the values ​​to be displayed and the values ​​that can be changed<br>
 can be adjusted with the 'detail-level' and 'setting-level' attributes. 
</ul>

<b>Get</b>
<br>
<ul>

  <li><b> get &lt;name&gt; data </b>
  <br><br>
  The request of the charger will be executed directly. Otherwise all <intervall> seconds the charge will be called automated (look at attribute interval)
  <br>
  </li>
  <li><b> get &lt;name&gt; showAccount </b>
  <br><br>
  Shows the decrypted account infos
  <br>
  </li>

<br>
</ul>

<b>Attributes</b>
<ul>
  <a name="disable"></a>
  <li><b>disable [1|0]</b><br>
    Deactivate/activate the module.
  </li>
  <br>

  <a name="interval"></a>
  <li><b>interval </b><br>
    Request cycle in seconds. (default: 60)
  </li>
  <br>
  
  <a name="detail-level"></a>
  <li><b>detail-level</b><br>
    Set level for showing Live-Data Readings<br>
	0: Basic<br>
	1: Adanced<br>
	2: Expert
  </li>
  <br>
  
  <a name="setting-level"></a>
  <li><b>setting-level</b><br>
    Set level for changing Parameters with fhem set-command. The module checks corresponding detail-level attribute.<br>
	0: Basic<br>
	1: Adanced<br>
	2: Expert
  </li>
  <br>

</ul>

<b>Readings</b>
<ul>
Following infos will show readings (livedata, parameter) and there corresponding detail-level and setting-level.

There are additional readings which will be calculated from the values of the wallbox.

<a name="Anzahl_Ladevorgaenge"></a>
  <li><b>Anzahl_Ladevorgaenge</b><br>
    Counts the charging starts since last connecting
  </li>
  <br>
  <a name="Startzeit_Verbindung"></a>
  <li><b>Startzeit_Verbindung</b><br>
    Last connecting time
  </li>
  <br>
</ul>
<br>

To start charging there are different options:
<ul>
<a name="Param_Betriebsart_Ladevorgang"></a>
  <li><b>Param_Betriebsart_Ladevorgang</b><br>
    Optimiertes Laden: default for using planning algorithm from wallbox<br>
	Laden mit Vorgabe: predefined charging. To set this option the params 'Param_Dauer_Ladevorgang' and 'Param_Energiemenge_Ladevorgang' must be filled.<br>
	If both values are set then this param will be set automatically and charging starts.<br>
	Ladestopp: stop charging
  </li>
  <br>
  <a name="Param_Dauer_Ladevorgang"></a>
  <li><b>Param_Dauer_Ladevorgang</b><br>
    Duration of the charging process. This values sets date/time till charging should be finished (Param_Ende_Ladevorgang)
  </li>
  <br>
  <a name="Param_Energiemenge_Ladevorgang"></a>
  <li><b>Param_Energiemenge_Ladevorgang</b><br>
    Set energy for charging in kWh. Value can be changed during charging process.
  </li>
  <br>
  <a name="Param_Minimaler_Ladestrom"></a>
  <li><b>Param_Minimaler_Ladestrom</b><br>
    Set minimum power for starting charging process. Minimum is 6A. Some vehicles need more power to start, so change this value.
  </li>
  <br>
</ul>
<br>



<ul>
<li>Name in Webinterface :<b> Name in FHEM </b> : comment</li>
					<li><b>LIVEDATA</b></li>
					<li>Measurement.ChaSess.WhIn :<b>Energie_Ladevorgang : unit Wh (detail-level: 0)</b></li>
					<li>Measurement.Chrg.ModSw :<b>Schalterstellung Drehschalter : (detail-level: 0)</b></li>
					<li>Measurement.GridMs.A.phsA :<b> Netzstrom_Phase_L1</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.A.phsB :<b> Netzstrom_Phase_L2</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.A.phsC :<b> Netzstrom_Phase_L3</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsA :<b> Netzspannung_Phase_L1</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsB :<b> Netzspannung_Phase_L2</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsC :<b> Netzspannung_Phase_L3</b> : (detail-level: 0)</li>
					<li>Measurement.Metering.GridMs.TotWIn :<b> Leistung_Bezug</b> : unit: W (detail-level: 0)</li>
					<li>Measurement.Metering.GridMs.TotWIn.ChaSta :<b> Leistung_Ladestation</b> : unit W (detail-level: 0)</li> 
					<li>Measurement.Metering.GridMs.TotWhIn :<b> Zaehlerstand_Bezugszaehler</b> : unit Wh (detail-level: 0)</li>  
					<li>Measurement.Metering.GridMs.TotWhIn.ChaSta :<b> Zaehlerstand_Ladestation</b> : unit Wh (detail-level: 0)</li>
					<li>Measurement.Operation.EVeh.ChaStt :<b> Status_Ladevorgang</b>: (detail-level: 0)</li> 
					<li>Measurement.Operation.EVeh.Health :<b> Status_verbundenes_Fahrzeug</b>: (detail-level: 0)</li> 
					<li>Measurement.Operation.Evt.Msg :<b> Status_Meldung</b> : (detail-level: 0)</li> 
					<li>Measurement.Operation.Health :<b> Status_Zustand</b> : (detail-level: 0)</li> 
					<li>Setpoint.PlantControl.Inverter.FstStop : <b> Schnellabschaltung </b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.Hz :<b> Netzfrequenz</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotPF :<b> Verschiebungsfaktor</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotVA :<b> Scheinleistung</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotVAr :<b> Blindleistung</b> : (detail-level: 1)</li>
					<li>Measurement.Wl.AcqStt :<b> Status_WLAN_Scan</b> : (detail-level: 1)</li>
					<li>Measurement.Wl.ConnStt :<b> Status_WLAN_Verbindung</b> : (detail-level: 1)</li> 
					<li>Measurement.Wl.SigPwr :<b> Signalstaerke_Netzwerk</b> : (detail-level: 1)</li> 
   					<li>Measurement.InOut.GI1 :<b> digitaler_Gruppeneingang</b> : (detail-level: 2)</li>
					<li>Measurement.Operation.WMaxLimSrc :<b> Digitaler_Eingang</b> : (detail-level: 2)</li>
					<li>Measurement.Wl.SoftAcsConnStt :<b> Status_Soft_Access_Point</b> : (detail-level: 2)</li> 
					<li><b>PARAMS:</b></li>
					<li>Parameter.Chrg.ActChaMod :<b> Param_Betriebsart_Ladevorgang</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.AMinCha :<b> Param_Minimaler_Ladestrom</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.DurTmm :<b> Param_Dauer_Ladevorgang</b> : (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.En :<b> Param_Energiemenge_Ladevorgang</b> : (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.StopTm :<b> Param_Ende_Ladevorgang</b>: (detail-level: 0) </li>
					<li>Parameter.Chrg.StpWhenFl :<b> Param_Trennung_nach_Vollladung</b>: (detail-level: 0 / setting-level: 1)</li>
					<li>Parameter.Chrg.StpWhenFlTm :<b> Param_Ladebereitschaft_bis_Trennung</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.Chrg.ChrgApv :<b> Param_Manuelle_Ladefreigabe</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.ChrgLok :<b> Param_Ladefreigabe_ueber_App</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.GridGuard.Cntry.VRtg :<b> Param_Netz_Nennspannung</b>: (detail-level: 0) </li>
					<li>Parameter.PCC.ARtg :<b> Param_Nennstrom_Netzanschluss</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.PCC.FlbInv.WMax :<b> Param_Fallback_Wirkleistungsbegrenzung</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.Chrg.UseEnergyMeter :<b> Param_Betrieb_mit_Netzanschlusspunktzaehler</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Chrg.MinSwTms :<b> Param_Minimale_Schaltdauer_Relais</b> : (detail-level: 1 / setting-level: 1) </li>
					<li>Parameter.Inverter.WMax :<b> Param_Nennwirkleistung_WMaxOut</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Inverter.WMaxIn :<b> Param_Nennwirkleistung_WMaxIn</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Inverter.WMaxInRtg :<b> Param_Bemessungswirkleistung_WMaxInRtg</b>: (detail-level: 1)</li>
					<li>Parameter.Inverter.AcALim :<b> Param_AC_Strom_Begrenzung</b>: (detail-level: 0 / setting-level: 1)</li>
					<li>Parameter.Nameplate.ARtg :<b> Param_Nennstrom_alle_Phasen</b>: (detail-level: 1)</li>
					<li>Parameter.Nameplate.Location : <b> Param_Geraetename </b> : (detail-level: 1)</li>
					<li>Parameter.PCC.WMaxAsym :<b> Param_Maximale_Schieflast</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Nameplate.ChrgCtrl.ChrgTypTxt :<b>Param_Typ_Ladecontroller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SerNumTxt :<b>Param_Seriennummer_Ladecontrollers </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SusyId :<b>Param_SusyID_Ladecontrollers </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SwRevTxt :<b>Param_SWVersion_Ladecontroller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.HwRev :<b>Param_HWVersion_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.Rev :<b>Param_Umbaustand_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.SerNum :<b>Param_Seriennummer_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.SusyId :<b>Param_SUSyID_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpOS.SwRev :<b>Param_Firmware_Version_Betriebssystem </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.MacId :<b>Param_MAC-Adresse </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.MainModel :<b>Param_Geraeteklasse </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.Model :<b>Param_Geraetetyp </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ModelStr :<b>Param_Typenbezeichnung </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.PkgRev :<b>Param_Softwarepaket </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.SerNum :<b>Param_Seriennummer </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.Vendor :<b>Param_Hersteller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.WlMacId :<b>Param_WLAN_MAC </b>: (detail-level: 2) </li>
					<li>Parameter.DevUpd.IsOn :<b> Param_Geraete_Update_ein</b> : (detail-level: 2)</li>
					<li>Parameter.Inverter.OutPhs :<b> Param_Phasenzuordnung</b> : (detail-level: 2)</li>
					<li>Parameter.Operation.ComTmOut :<b> Param_Timeout_nach_Kommunikationsverlust</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.IgmpQryTms :<b> Param_IGMP_Query_Intervall</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.IgmpQryTx :<b> Param_IGMP_Anfragen_senden</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlDnsSrvIp :<b>Param_Akt_Speedwire_Serveradresse </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlGwIp :<b>Param_Akt_Speedwire_Gateway </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlIp :<b>Param_Akt_Speedwire_IP </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlSnetMsk :<b>Param_Akt_Speedwire_Subnetzmaske </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.AutoCfgIsOn :<b>Automatische_Speedwire-Konfig_an </b>: (detail-level: 2) </li>
					<li>Parameter.Sys.DevRstr :<b> Param_Geraeteneustart_ausloesen</b>: (detail-level: 2) </li>
					<li>Parameter.SwCmp.CmpEnnexOS.Frwk.SwRev :<b>Param_ennexOS_Framework_Version </b>: (detail-level: 2) </li>
					<li>Parameter.Upd.AutoUpdIsOn :<b> Param_Auto_Update_an</b>: (detail-level: 2) </li>
					<li>Parameter.Upd.AvalChkIstl :<b>Param_Auto_Speedwire_Konfig_an </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlGwIp :<b>Param_IP_Gateway_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlDnsSrvIp :<b>Aktuelle_Speedwire-DNS-Serveradresse </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlIp :<b>Param_IP_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlSnetMsk :<b>Param_IP_Subnetz_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.DoAcq :<b>Param_WLAN_suchen </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.DoWPS :<b>Param_WPS_aktivieren </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ExsNetw[] :<b>Param_Gefundenes_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Cry :<b>Param_Verschluesselung_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Psk :<b>Param_WLAN-Passwort </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Ssid :<b>Param_SSID_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.AutoCfgIsOn :<b> Param_Auto_Update_an</b>: (detail-level: 2) </li>
					<li>Parameter.Wl.IsOn :<b> Param_WLAN_eingeschaltet</b>: (detail-level: 2) </li>
					<li>Parameter.Wl.SoftAcsIsOn :<b> Param_Soft_Access_Point_an</b>: (detail-level: 2) </li>
</ul>
<br><br>


=end html


=begin html_DE

<a name="SMAEVCharger"></a>
<h3>SMAEVCharger</h3>

Modul zur Integration eines SMA EVCharger über Speedwire (=Ethernet) Schnittstelle.<br>
Getestet mit SMA EV Charger 22
<br><br>

<!--
Fragen und Diskussionen sind im FHEM Forum unter folgenden Link zu finden:<br>
<a href="https://forum.fhem.de/index.php/topic,116543.msg1119664.html#msg1119664">SMA EV-Charger</a>.
<br><br>
-->

<b>Notwendige Module</b>
<br><br>
Diese Modul benötigt:
<ul>
    <li>Perl Module: Date::Time        (apt-get install libdatetime-perl) </li>
	<li>Perl Module: Time::HiRes</li>
	<li>Perl Module: JSON</li>
	<li>FHEM Module: Blocking.pm</li>
</ul>
<br>
<br>


<b>Definition</b>
<ul>
<code>define &lt;name&gt; SMAEVCharger &lt;hostname/ip&gt; &lt;user&gt; &lt;password&gt;  </code><br>
<br>
<li>hostname/ip: IP-Adress des Charger, sollte zunächst ohne Protokoll angegeben werden (mit hostname noch nicht getestet!).</li>
<li>Beispiel: define myWallbox 192.168.xxx.xxx username userpassword</li>
</ul>


<b>Operation method</b>
<ul>
Das Modul meldet sich bei der SMA Wallbox an und liest Live-Daten (Momentanwerte) sowie verfügbare Parameter (Konfigurationsparameter).<br>
Alle Werte, die über die Weboberfläche geändert werden können, können auch mit dem Modul geändert werden. Um die Readings zu reduzieren, <br>
können die anzuzeigenden Werte und die Werte, die geändert werden können, mit den Attributen "detail-level" und "setting-level" angepasst werden.
</ul>

<b>Get</b>
<br>
<ul>

  <li><b> get &lt;name&gt; data </b>
  <br><br>
  Die Daten des Chargers werden direkt abgerufen. Ansonsten findet alle <intervall> Sekunden ein automatisierter Abruf statt (siehe auch das Attribut interval)
  <br>
  </li>
  <li><b> get &lt;name&gt; showAccount </b>
  <br><br>
  Zeigt die unverschlüsselten Anmeldedaten an
  <br>
  </li>

<br>
</ul>

<b>Attribute</b>
<ul>
  <a name="disable"></a>
  <li><b>disable [1|0]</b><br>
    Deaktivieren/Aktivieren des Moduls.
  </li>
  <br>

  <a name="interval"></a>
  <li><b>interval </b><br>
    Abfragezyklus in Sekunden. (default: 60)
  </li>
  <br>
  
  <a name="detail-level"></a>
  <li><b>detail-level</b><br>
    Einstellung der Sichtbarkeit von Parametern.<br>
	0: Basisinformationen<br>
	1: erweiterte Informationen<br>
	2: Infos auf Expertenlevel
  </li>
  <br>
  
  <a name="setting-level"></a>
  <li><b>setting-level</b><br>
    Einstellung für die Parameter, die über den set-Befehl änderbar sind. Bei der Eingabe wird geprüft, dass diese auch mittels "detail-level" sichtbar sind<br>
	0: Basisinformationen<br>
	1: erweiterte Änderungsparameter<br>
	2: Änderung von Parametern auf Expertenlevel
  </li>
  <br>
</ul>

<b>Readings</b>

Nachfolgende Readings dienen der Darstellung zusätzlicher Werte, die aus den Werten der Wallbox ermittelt wurden.
<ul>
<a name="Anzahl_Ladevorgaenge"></a>
  <li><b>Anzahl_Ladevorgaenge</b><br>
    Zähler zur Ermittlung aller gestarteten Ladungen, seit dem der Stecker das letzte Mal eingesteckt wurde
  </li>
  <br>
  <a name="Startzeit_Verbindung"></a>
  <li><b>Startzeit_Verbindung</b><br>
    Zeitpunkt, zu dem der Stecker das letzte Mal angesteckt wurde
  </li>
  <br>
</ul>
<br>

Zum Starten des Ladeprozess gibt es verschiedene Einstellmöglichkeiten:
<ul>
<a name="Param_Betriebsart_Ladevorgang"></a>
  <li><b>Param_Betriebsart_Ladevorgang</b><br>
    Optimiertes Laden: Standardeinstellung für die Ladesteuerung der Wallbox<br>
	Laden mit Vorgabe: Laden mit vordefinierten Werten. Dieser Wert kann nur eingestellt werden, wenn die Parameter 'Param_Dauer_Ladevorgang' und 'Param_Energiemenge_Ladevorgang' gefüllt sind.<br>
	Sind beide Werte gesetzt, wird automatisch in diesen Lademodus geschaltet und die Ladung beginnt entsprechend<br>
	Ladestopp: Ladevorgang stoppen
  </li>
  <br>
  <a name="Param_Dauer_Ladevorgang"></a>
  <li><b>Param_Dauer_Ladevorgang</b><br>
    Dauer des Ladevorgangs in Minuten. Hiermit wird dann auch der Parameter 'Param_Ende_Ladevorgang' gesetzt, der Datum/Uhrzeit des geplanten Ladeende anzeigt
  </li>
  <br>
  <a name="Param_Energiemenge_Ladevorgang"></a>
  <li><b>Param_Energiemenge_Ladevorgang</b><br>
    Energiemenge in kWh, die in der angegebenen Zeit geladen werden soll
  </li>
  <br>
  <a name="Param_Minimaler_Ladestrom"></a>
  <li><b>Param_Minimaler_Ladestrom</b><br>
    Minimaler Strom, mit dem eine Ladung gestartet wird. Minimum ist 6A. Einige E-Autos benötigen einen höheren Wert, der hiermit eingestellt werden kann.
  </li>
  <br>
</ul>
<br>


Nachfolgend sind alle Readings aufgelistet:

<br>
<ul>
<li>Name im Webinterface :<b> Name in FHEM </b> : Kommentar</li>
<li><b>LIVEDATA</b></li>
					<li>Measurement.ChaSess.WhIn :<b>Energie_Ladevorgang : unit Wh (detail-level: 0)</b></li>
					<li>Measurement.Chrg.ModSw :<b>Schalterstellung Drehschalter : (detail-level: 0)</b></li>
					<li>Measurement.GridMs.A.phsA :<b> Netzstrom_Phase_L1</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.A.phsB :<b> Netzstrom_Phase_L2</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.A.phsC :<b> Netzstrom_Phase_L3</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsA :<b> Netzspannung_Phase_L1</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsB :<b> Netzspannung_Phase_L2</b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.PhV.phsC :<b> Netzspannung_Phase_L3</b> : (detail-level: 0)</li>
					<li>Measurement.Metering.GridMs.TotWIn :<b> Leistung_Bezug</b> : unit: W (detail-level: 0)</li>
					<li>Measurement.Metering.GridMs.TotWIn.ChaSta :<b> Leistung_Ladestation</b> : unit W (detail-level: 0)</li> 
					<li>Measurement.Metering.GridMs.TotWhIn :<b> Zaehlerstand_Bezugszaehler</b> : unit Wh (detail-level: 0)</li>  
					<li>Measurement.Metering.GridMs.TotWhIn.ChaSta :<b> Zaehlerstand_Ladestation</b> : unit Wh (detail-level: 0)</li>
					<li>Measurement.Operation.EVeh.ChaStt :<b> Status_Ladevorgang</b>: (detail-level: 0)</li> 
					<li>Measurement.Operation.EVeh.Health :<b> Status_verbundenes_Fahrzeug</b>: (detail-level: 0)</li> 
					<li>Measurement.Operation.Evt.Msg :<b> Status_Meldung</b> : (detail-level: 0)</li> 
					<li>Measurement.Operation.Health :<b> Status_Zustand</b> : (detail-level: 0)</li> 
					<li>Setpoint.PlantControl.Inverter.FstStop : <b> Schnellabschaltung </b> : (detail-level: 0)</li>
					<li>Measurement.GridMs.Hz :<b> Netzfrequenz</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotPF :<b> Verschiebungsfaktor</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotVA :<b> Scheinleistung</b> : (detail-level: 1)</li>
					<li>Measurement.GridMs.TotVAr :<b> Blindleistung</b> : (detail-level: 1)</li>
					<li>Measurement.Wl.AcqStt :<b> Status_WLAN_Scan</b> : (detail-level: 1)</li>
					<li>Measurement.Wl.ConnStt :<b> Status_WLAN_Verbindung</b> : (detail-level: 1)</li> 
					<li>Measurement.Wl.SigPwr :<b> Signalstaerke_Netzwerk</b> : (detail-level: 1)</li> 
   					<li>Measurement.InOut.GI1 :<b> digitaler_Gruppeneingang</b> : (detail-level: 2)</li>
					<li>Measurement.Operation.WMaxLimSrc :<b> Digitaler_Eingang</b> : (detail-level: 2)</li>
					<li>Measurement.Wl.SoftAcsConnStt :<b> Status_Soft_Access_Point</b> : (detail-level: 2)</li> 
					<li><b>PARAMS:</b></li>
					<li>Parameter.Chrg.ActChaMod :<b> Param_Betriebsart_Ladevorgang</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.AMinCha :<b> Param_Minimaler_Ladestrom</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.DurTmm :<b> Param_Dauer_Ladevorgang</b> : (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.En :<b> Param_Energiemenge_Ladevorgang</b> : (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.Plan.StopTm :<b> Param_Ende_Ladevorgang</b>: (detail-level: 0) </li>
					<li>Parameter.Chrg.StpWhenFl :<b> Param_Trennung_nach_Vollladung</b>: (detail-level: 0 / setting-level: 1)</li>
					<li>Parameter.Chrg.StpWhenFlTm :<b> Param_Ladebereitschaft_bis_Trennung</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.Chrg.ChrgApv :<b> Param_Manuelle_Ladefreigabe</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.Chrg.ChrgLok :<b> Param_Ladefreigabe_ueber_App</b>: (detail-level: 0 / setting-level: 0) </li>
					<li>Parameter.GridGuard.Cntry.VRtg :<b> Param_Netz_Nennspannung</b>: (detail-level: 0) </li>
					<li>Parameter.PCC.ARtg :<b> Param_Nennstrom_Netzanschluss</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.PCC.FlbInv.WMax :<b> Param_Fallback_Wirkleistungsbegrenzung</b>: (detail-level: 0 / setting-level: 1) </li>
					<li>Parameter.Chrg.UseEnergyMeter :<b> Param_Betrieb_mit_Netzanschlusspunktzaehler</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Chrg.MinSwTms :<b> Param_Minimale_Schaltdauer_Relais</b> : (detail-level: 1 / setting-level: 1) </li>
					<li>Parameter.Inverter.WMax :<b> Param_Nennwirkleistung_WMaxOut</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Inverter.WMaxIn :<b> Param_Nennwirkleistung_WMaxIn</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Inverter.WMaxInRtg :<b> Param_Bemessungswirkleistung_WMaxInRtg</b>: (detail-level: 1)</li>
					<li>Parameter.Inverter.AcALim :<b> Param_AC_Strom_Begrenzung</b>: (detail-level: 0 / setting-level: 1)</li>
					<li>Parameter.Nameplate.ARtg :<b> Param_Nennstrom_alle_Phasen</b>: (detail-level: 1)</li>
					<li>Parameter.Nameplate.Location : <b> Param_Geraetename </b> : (detail-level: 1)</li>
					<li>Parameter.PCC.WMaxAsym :<b> Param_Maximale_Schieflast</b>: (detail-level: 1 / setting-level: 1)</li>
					<li>Parameter.Nameplate.ChrgCtrl.ChrgTypTxt :<b>Param_Typ_Ladecontroller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SerNumTxt :<b>Param_Seriennummer_Ladecontrollers </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SusyId :<b>Param_SusyID_Ladecontrollers </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ChrgCtrl.SwRevTxt :<b>Param_SWVersion_Ladecontroller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.HwRev :<b>Param_HWVersion_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.Rev :<b>Param_Umbaustand_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.SerNum :<b>Param_Seriennummer_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpMain.SusyId :<b>Param_SUSyID_Hauptprozessor </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.CmpOS.SwRev :<b>Param_Firmware_Version_Betriebssystem </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.MacId :<b>Param_MAC-Adresse </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.MainModel :<b>Param_Geraeteklasse </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.Model :<b>Param_Geraetetyp </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.ModelStr :<b>Param_Typenbezeichnung </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.PkgRev :<b>Param_Softwarepaket </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.SerNum :<b>Param_Seriennummer </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.Vendor :<b>Param_Hersteller </b>: (detail-level: 2) </li>
					<li>Parameter.Nameplate.WlMacId :<b>Param_WLAN_MAC </b>: (detail-level: 2) </li>
					<li>Parameter.DevUpd.IsOn :<b> Param_Geraete_Update_ein</b> : (detail-level: 2)</li>
					<li>Parameter.Inverter.OutPhs :<b> Param_Phasenzuordnung</b> : (detail-level: 2)</li>
					<li>Parameter.Operation.ComTmOut :<b> Param_Timeout_nach_Kommunikationsverlust</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.IgmpQryTms :<b> Param_IGMP_Query_Intervall</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.IgmpQryTx :<b> Param_IGMP_Anfragen_senden</b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlDnsSrvIp :<b>Param_Akt_Speedwire_Serveradresse </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlGwIp :<b>Param_Akt_Speedwire_Gateway </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlIp :<b>Param_Akt_Speedwire_IP </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.ActlSnetMsk :<b>Param_Akt_Speedwire_Subnetzmaske </b>: (detail-level: 2) </li>
					<li>Parameter.Spdwr.AutoCfgIsOn :<b>Automatische_Speedwire-Konfig_an </b>: (detail-level: 2) </li>
					<li>Parameter.Sys.DevRstr :<b> Param_Geraeteneustart_ausloesen</b>: (detail-level: 2) </li>
					<li>Parameter.SwCmp.CmpEnnexOS.Frwk.SwRev :<b>Param_ennexOS_Framework_Version </b>: (detail-level: 2) </li>
					<li>Parameter.Upd.AutoUpdIsOn :<b> Param_Auto_Update_an</b>: (detail-level: 2) </li>
					<li>Parameter.Upd.AvalChkIstl :<b>Param_Auto_Speedwire_Konfig_an </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlGwIp :<b>Param_IP_Gateway_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlDnsSrvIp :<b>Aktuelle_Speedwire-DNS-Serveradresse </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlIp :<b>Param_IP_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ActlSnetMsk :<b>Param_IP_Subnetz_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.DoAcq :<b>Param_WLAN_suchen </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.DoWPS :<b>Param_WPS_aktivieren </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.ExsNetw[] :<b>Param_Gefundenes_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Cry :<b>Param_Verschluesselung_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Psk :<b>Param_WLAN-Passwort </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.Sec.Ssid :<b>Param_SSID_WLAN </b>: (detail-level: 2) </li>
					<li>Parameter.Wl.AutoCfgIsOn :<b> Param_Auto_Update_an</b>: (detail-level: 2) </li>
					<li>Parameter.Wl.IsOn :<b> Param_WLAN_eingeschaltet</b>: (detail-level: 2) </li>
					<li>Parameter.Wl.SoftAcsIsOn :<b> Param_Soft_Access_Point_an</b>: (detail-level: 2) </li>
</ul>

<br><br>

=end html_DE

=cut
