From d3a1ed9fbd9f7043fd5df8b0fcc4cb6afea1155c Mon Sep 17 00:00:00 2001 From: Matthias Sandmann Date: Sat, 26 Mar 2022 23:20:30 +0100 Subject: [PATCH] added second half of the script. Issue of patch was the regex containing # which must be escaped in regex extended --- 98_EaseeWallbox.pm | 743 ++++++++++++++++++++++++++------------------- 1 file changed, 434 insertions(+), 309 deletions(-) diff --git a/98_EaseeWallbox.pm b/98_EaseeWallbox.pm index 3000264..6a6dc61 100644 --- a/98_EaseeWallbox.pm +++ b/98_EaseeWallbox.pm @@ -1,7 +1,5 @@ package FHEM::EaseeWallbox; -# use GPUtils qw(GP_Import GP_Export); hast Du auch weiter unten stehen - use strict; use warnings; use Data::Dumper; @@ -70,9 +68,7 @@ eval { # Import von Funktionen und/oder Variablen aus der FHEM main # man kann ::Funktionaname wählen und sich so den Import schenken. Variablen sollten aber # sauber importiert werden -# use GPUtils qw(GP_Import); -use GPUtils qw(GP_Import GP_Export) - ; # da Du beide Funktionen aus dem package verwendest +use GPUtils qw(GP_Import GP_Export); ## Import der FHEM Funktionen #-- Run before package compilation @@ -154,8 +150,8 @@ my %dpoints = ( getCurrentSession => 'chargers/#ChargerID#/sessions/ongoing', setCableLockState => 'chargers/#ChargerID#/commands/lock_state', setReboot => 'chargers/#ChargerID#/commands/reboot', - setUpdateFirmware => 'chargers/#ChargerID#/commands/update_firmware', - setEnableSmartCharging => 'chargers/#ChargerID#/commands/smart_charging', + setUpdateFirmware => 'chargers/#ChargerID#/commands/update_firmware', + setEnableSmartCharging => 'chargers/#ChargerID#/commands/smart_charging', setStartCharging => 'chargers/#ChargerID#/commands/start_charging', setStopCharging => 'chargers/#ChargerID#/commands/stop_charging', setPauseCharging => 'chargers/#ChargerID#/commands/pause_charging', @@ -230,9 +226,6 @@ my %commandCodes = ( ); #Private function to evaluate command-lists -# private funktionen beginnen immer mit _ - -############################# sub _GetCmdList { my ( $hash, $cmd, $commands ) = @_; @@ -265,13 +258,7 @@ sub _GetCmdList { if ( !defined($retVal) ) { return "error while parsing set-table"; } - return "Unknown argument $cmd, choose one of " . $retVal; - - # versuche wo wenig wie möglich if else zu verwenden. - # else { - # $retVal = "Unknown argument $cmd, choose one of " . $retVal; - # } } sub Initialize { @@ -302,15 +289,12 @@ sub Define { # set API URI as Internal Key $hash->{APIURI} = 'https://api.easee.cloud/api/'; - Log3 $name, 3, "EaseeWallbox_Define $name: called "; - my $errmsg = ''; - -# Check parameter(s) - Must be min 4 in total (counts strings not purly parameter, interval is optional) + # Check parameter(s) - Must be min 4 in total (counts strings not purly parameter, interval is optional) if ( int(@param) < 4 ) { $errmsg = return -"syntax error: define EaseeWallbox [Interval]"; + "syntax error: define EaseeWallbox [Interval]"; Log3 $name, 1, "EaseeWallbox $name: " . $errmsg; return $errmsg; } @@ -323,7 +307,7 @@ sub Define { } else { $errmsg = -"specify valid email address within the field username. Format: define EaseeWallbox [interval]"; + "specify valid email address within the field username. Format: define EaseeWallbox [interval]"; Log3 $name, 1, "EaseeWallbox $name: " . $errmsg; return $errmsg; } @@ -568,54 +552,60 @@ sub UpdateDueToTimer { } sub WriteToCloudAPI { - my $hash = shift; - my $dpoint = shift; - my $method = shift; + my $hash = shift; + my $dpoint = shift; + my $method = shift; my $message = shift; - my $name = $hash->{NAME}; - my $url = $hash->{APIURI} . $dpoints{$dpoint}; + my $name = $hash->{NAME}; + my $url = $hash->{APIURI} . $dpoints{$dpoint}; ######### # CHANGE THIS my $payload; - $payload = encode_json \%$message if defined $message; + $payload = encode_json \%$message if defined $message; my $deviceId = "WC1"; - if ( not defined $hash ) { - my $msg = "Error on EaseeWallbox_WriteToCloudAPI. Missing hash variable"; + if ( not defined $hash ) { + my $msg = + "Error on EaseeWallbox_WriteToCloudAPI. Missing hash variable"; Log3 'EaseeWallbox', 1, $msg; return $msg; } #Check if chargerID is required in URL and replace or alert. - if ( $url =~ m/#ChargerID#/ ) { + if ( $url =~ m/\#ChargerID\#/x ) + { # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) my $chargerId = ReadingsVal( $name, 'charger_id', undef ); if ( not defined $chargerId ) { - my $error = "Error on EaseeWallbox_WriteToCloudAPI. Missing charger_id. Please ensure basic data is available."; + my $error = +"Error on EaseeWallbox_WriteToCloudAPI. Missing charger_id. Please ensure basic data is available."; Log3 'EaseeWallbox', 1, $error; return $error; } - $url =~ s/#ChargerID#/$chargerId/g; + $url =~ s/\#ChargerID\#/$chargerId/xg + ; # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) } #Check if siteID is required in URL and replace or alert. - if ( $url =~ m/#SiteID#/ ) { + if ( $url =~ m/\#SiteID\#/x ) + { # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) my $siteId = ReadingsVal( $name, 'site_id', undef ); if ( not defined $siteId ) { - my $error = "Error on EaseeWallbox_WriteToCloudAPI. Missing site_id. Please ensure basic data is available."; + my $error = +"Error on EaseeWallbox_WriteToCloudAPI. Missing site_id. Please ensure basic data is available."; Log3 'EaseeWallbox', 1, $error; return $error; } - $url =~ s/#SiteID#/$siteId/g; + $url =~ s/\#SiteID\#/$siteId/xg + ; # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) } my $CurrentTokenData = _loadToken($hash); - my $header = - { - "Content-Type" => "application/json;charset=UTF-8", - "Authorization" => - "$CurrentTokenData->{'tokenType'} $CurrentTokenData->{'accessToken'}" - }; + my $header = { + "Content-Type" => "application/json;charset=UTF-8", + "Authorization" => + "$CurrentTokenData->{'tokenType'} $CurrentTokenData->{'accessToken'}" + }; # $method ist GET oder POST # bei POST ist $payload gleich data @@ -641,288 +631,409 @@ sub ResponseHandling { my $param = shift; my $err = shift; my $data = shift; - my $hash = $param->{hash}; - my $name = $hash->{NAME}; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; Log3 $name, 4, "Callback received." . $param->{url}; - if ( $err ne "" ) # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist + if ( $err ne "" ) # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist { - Log3 $name, 3,"error while requesting ". $param->{url}. " - $err"; # Eintrag fürs Log + Log3 $name, 3, + "error while requesting " + . $param->{url} + . " - $err"; # Eintrag fürs Log readingsSingleUpdate( $hash, "lastResponse", "ERROR $err", 1 ); - return undef; + return; } my $code = $param->{code}; - if ($code eq 404 and $param->{dpoint} eq 'getCurrentSession'){ - readingsDelete($hash, 'session_energy' ); - readingsDelete($hash, 'session_start' ); - readingsDelete($hash, 'session_end' ); - readingsDelete($hash, 'session_chargeDurationInSeconds' ); - readingsDelete($hash, 'session_firstEnergyTransfer' ); - readingsDelete($hash, 'session_lastEnergyTransfer' ); - readingsDelete($hash, 'session_pricePerKWH' ); - readingsDelete($hash, 'session_chargingCost' ); - readingsDelete($hash, 'session_id' ); - return undef; + if ( $code == 404 and $param->{dpoint} eq 'getCurrentSession' ) + { # Entweder == dann number z.B. 404 oder wenn eq dann String also '404' + readingsDelete( $hash, 'session_energy' ); + readingsDelete( $hash, 'session_start' ); + readingsDelete( $hash, 'session_end' ); + readingsDelete( $hash, 'session_chargeDurationInSeconds' ); + readingsDelete( $hash, 'session_firstEnergyTransfer' ); + readingsDelete( $hash, 'session_lastEnergyTransfer' ); + readingsDelete( $hash, 'session_pricePerKWH' ); + readingsDelete( $hash, 'session_chargingCost' ); + readingsDelete( $hash, 'session_id' ); + return; } - if ($code >= 400){ - Log3 $name, 3,"HTTPS error while requesting ". $param->{url}. " - $code"; # Eintrag fürs Log - readingsSingleUpdate( $hash, "lastResponse", "ERROR: HTTP Code $code", 1 ); - return undef; + if ( $code >= 400 ) { + Log3 $name, 3, + "HTTPS error while requesting " + . $param->{url} + . " - $code"; # Eintrag fürs Log + readingsSingleUpdate( $hash, "lastResponse", "ERROR: HTTP Code $code", + 1 ); + return; } Log3 $name, 3, - "Received non-blocking data from EaseeWallbox regarding current session "; + "Received non-blocking data from EaseeWallbox regarding current session "; Log3 $name, 4, "FHEM -> EaseeWallbox: " . $param->{url}; Log3 $name, 4, "FHEM -> EaseeWallbox: " . $param->{message} - if ( defined $param->{message} ); + if ( defined $param->{message} ); Log3 $name, 4, "EaseeWallbox -> FHEM: " . $data; Log3 $name, 5, '$err: ' . $err; Log3 $name, 5, "method: " . $param->{method}; Log3 $name, 2, "Something gone wrong" - if ( $data =~ "/EaseeWallboxMode/" ); - - my $d; - eval { - my $d = decode_json($data); - Log3 $name, 5, 'Decoded: ' . Dumper($d); - Log3 $name, 5, 'Ref of d: ' . ref($d); + if ( $data =~ "/EaseeWallboxMode/" ); - if ( defined $d and $d ne '' and ref($d) eq "HASH" or (ref($d) eq "ARRAY" and $d gt 0)) { - if($param->{dpoint} eq 'getChargers') - { - my $site = $d->[0]; - my $circuit = $site->{circuits}->[0]; - my $charger = $circuit->{chargers}->[0]; + my $decoded_json; - readingsBeginUpdate($hash); - my $chargerId = $charger->{id}; - readingsBulkUpdate( $hash, "site_id", $site->{id} ); - readingsBulkUpdate( $hash, "site_key", $site->{siteKey} ); - readingsBulkUpdate( $hash, "charger_id", $chargerId ); - readingsBulkUpdate( $hash, "charger_name", $charger->{name} ); - readingsBulkUpdate( $hash, "lastResponse", 'OK - getReaders', 1); - readingsEndUpdate( $hash, 1 ); - WriteToCloudAPI($hash, 'getChargerConfiguration', 'GET'); - return; - } + eval { $decoded_json = decode_json($data) }; # statt eval ist es empfohlen catch try zu verwenden. Machen wir später + if ($@) { + Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request"; + } - if($param->{dpoint} eq 'getChargerSessionsDaily') - { - Log3 $name, 5, 'Evaluating getChargerSessionsDaily'; - my @x = $d; - my @a = (-5..-1); - readingsBeginUpdate($hash); - for(@a){ - Log3 $name, 5, 'laeuft noch: '. $_; - readingsBulkUpdate( $hash, "daily_".($_ +1)."_energy", sprintf("%.2f",$d->[$_]->{'totalEnergyUsage'}) ); - readingsBulkUpdate( $hash, "daily_".($_ +1)."_cost", sprintf("%.2f",$d->[$_]->{'totalCost'}) ); - } - readingsEndUpdate( $hash, 1 ); - return; - } + Log3 $name, 5, 'Decoded: ' . Dumper($decoded_json); + Log3 $name, 5, 'Ref of d: ' . ref($decoded_json); - if($param->{dpoint} eq 'getChargerSessionsMonthly') - { - Log3 $name, 5, 'Evaluating getChargerSessionsMonthly'; - my @x = $d; - my @a = (-6..-1); - readingsBeginUpdate($hash); - for(@a){ - Log3 $name, 5, 'laeuft noch: '. $_; - readingsBulkUpdate( $hash, "monthly_".($_ +1)."_energy", sprintf("%.2f",$d->[$_]->{'totalEnergyUsage'}) ); - readingsBulkUpdate( $hash, "monthly_".($_ +1)."_cost", sprintf("%.2f",$d->[$_]->{'totalCost'}) ); - } - readingsEndUpdate( $hash, 1 ); - return; - } + my $value; - - if($param->{dpoint} eq 'getChargerConfiguration') - { - readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, "isEnabled", $d->{isEnabled} ); - readingsBulkUpdate( $hash, "isCablePermanentlyLocked", $d->{lockCablePermanently} ); - readingsBulkUpdate($hash, "isAuthorizationRequired", $d->{authorizationRequired}); - readingsBulkUpdate( $hash, "isRemoteStartRequired", $d->{remoteStartRequired} ); - readingsBulkUpdate( $hash, "isSmartButtonEnabled", $d->{smartButtonEnabled} ); - readingsBulkUpdate( $hash, "wiFiSSID", $d->{wiFiSSID} ); - readingsBulkUpdate( $hash, "phaseModeId", $d->{phaseMode} ); - readingsBulkUpdate( $hash, "phaseMode",$phaseModes{ $d->{phaseMode} } ); - readingsBulkUpdate($hash, "isLocalAuthorizationRequired",$d->{localAuthorizationRequired}); - readingsBulkUpdate( $hash, "maxChargerCurrent", $d->{maxChargerCurrent} ); - readingsBulkUpdate( $hash, "ledStripBrightness", $d->{ledStripBrightness} ); - #readingsBulkUpdate( $hash, "charger_offlineChargingMode", - # $d->{offlineChargingMode} ); - #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP1", - # $d->{circuitMaxCurrentP1} ); - #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP2", - # $d->{circuitMaxCurrentP2} ); - #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP3", - # $d->{circuitMaxCurrentP3} ); - #readingsBulkUpdate( $hash, "charger_enableIdleCurrent", - # $d->{enableIdleCurrent} ); - #readingsBulkUpdate( - # $hash, - # "charger_limitToSinglePhaseCharging", - # $d->{limitToSinglePhaseCharging} - #); - - #readingsBulkUpdate( $hash, "charger_localNodeType", - # $d->{localNodeType} ); - - #readingsBulkUpdate( $hash, "charger_localRadioChannel", - # $d->{localRadioChannel} ); - #readingsBulkUpdate( $hash, "charger_localShortAddress", - # $d->{localShortAddress} ); - #readingsBulkUpdate( - # $hash, - # "charger_localParentAddrOrNumOfNodes", - # $d->{localParentAddrOrNumOfNodes} - #); - #readingsBulkUpdate( - # $hash, - # "charger_localPreAuthorizeEnabled", - # $d->{localPreAuthorizeEnabled} - #); - #readingsBulkUpdate( - # $hash, - # "charger_allowOfflineTxForUnknownId", - # $d->{allowOfflineTxForUnknownId} - #); - #readingsBulkUpdate( $hash, "chargingSchedule", - # $d->{chargingSchedule} ); - readingsBulkUpdate( $hash, "lastResponse", 'OK - getChargerConfig', 1); - readingsEndUpdate( $hash, 1 ); - return undef; - } - - if($param->{dpoint} eq 'getCurrentSession') - { - readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, "session_energy", sprintf("%.2f",$d->{sessionEnergy}) ); - my $value = defined $d->{sessionStart} ? _transcodeDate($d->{sessionStart}) : 'N/A'; - readingsBulkUpdate( $hash, "session_start", $value ); - my $value = defined $d->{sessionEnd} ? _transcodeDate($d->{sessionEnd}) : 'N/A'; - readingsBulkUpdate( $hash, "session_end", $value ); - readingsBulkUpdate( $hash, "session_chargeDurationInSeconds", $d->{chargeDurationInSeconds} ); - my $value = defined $d->{firstEnergyTransferPeriodStart} ? _transcodeDate($d->{firstEnergyTransferPeriodStart}) : 'N/A'; - readingsBulkUpdate( $hash, "session_firstEnergyTransfer", $value ); - my $value = defined $d->{lastEnergyTransferPeriodStart} ? _transcodeDate($d->{lastEnergyTransferPeriodStart}) : 'N/A'; - readingsBulkUpdate( $hash, "session_lastEnergyTransfer", $value ); - readingsBulkUpdate( $hash, "session_pricePerKWH", $d->{pricePrKwhIncludingVat} ); - readingsBulkUpdate( $hash, "session_chargingCost", sprintf("%.2f",$d->{costIncludingVat}) ); - readingsBulkUpdate( $hash, "session_id", $d->{sessionId} ); - readingsBulkUpdate( $hash, "lastResponse", 'OK - getCurrentSession', 1); - readingsEndUpdate( $hash, 1 ); - return undef; - } - - if($param->{dpoint} eq 'getChargerSite') - { - readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, "cost_perKWh", $d->{costPerKWh} ); - readingsBulkUpdate( $hash, "cost_perKwhExcludeVat", $d->{costPerKwhExcludeVat} ); - readingsBulkUpdate( $hash, "cost_vat", $d->{vat} ); - readingsBulkUpdate( $hash, "cost_currency", $d->{currencyId} ); - #readingsBulkUpdate( $hash, "site_ratedCurrent", $d->{ratedCurrent} ); - #readingsBulkUpdate( $hash, "site_createdOn", $d->{createdOn} ); - #readingsBulkUpdate( $hash, "site_updatedOn", $d->{updatedOn} ); - readingsBulkUpdate( $hash, "lastResponse", 'OK - getChargerSite', 1); - readingsEndUpdate( $hash, 1 ); - return undef; - } - - if($param->{dpoint} eq 'getChargerState') - { - readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, "operationModeCode", $d->{chargerOpMode} ); - readingsBulkUpdate( $hash, "operationMode", $operationModes{ $d->{chargerOpMode} } ); - readingsBulkUpdate( $hash, "power", sprintf("%.2f",$d->{totalPower}) ); - readingsBulkUpdate( $hash, "kWhInSession", sprintf("%.2f",$d->{sessionEnergy}) ); - readingsBulkUpdate( $hash, "phase", $d->{outputPhase} ); - readingsBulkUpdate( $hash, "latestPulse", _transcodeDate($d->{latestPulse}) ); - readingsBulkUpdate( $hash, "current", $d->{outputCurrent} ); - readingsBulkUpdate( $hash, "dynamicCurrent", $d->{dynamicChargerCurrent} ); - readingsBulkUpdate( $hash, "reasonCodeForNoCurrent", $d->{reasonForNoCurrent} ); - readingsBulkUpdate( $hash, "reasonForNoCurrent", $reasonsForNoCurrent{ $d->{reasonForNoCurrent} } ); - readingsBulkUpdate( $hash, "errorCode", $d->{errorCode} ); - readingsBulkUpdate( $hash, "fatalErrorCode", $d->{fatalErrorCode} ); - readingsBulkUpdate( $hash, "lifetimeEnergy", sprintf("%.2f",$d->{lifetimeEnergy}) ); - readingsBulkUpdate( $hash, "online", $d->{isOnline} ); - readingsBulkUpdate( $hash, "voltage", sprintf("%.2f",$d->{voltage}) ); - readingsBulkUpdate( $hash, "wifi_rssi", $d->{wiFiRSSI} ); - readingsBulkUpdate( $hash, "wifi_apEnabled", $d->{wiFiAPEnabled} ); - readingsBulkUpdate( $hash, "cell_rssi", $d->{cellRSSI} ); - readingsBulkUpdate( $hash, "lastResponse", 'OK - getChargerState', 1); - readingsEndUpdate( $hash, 1 ); - return undef; - } - - $d = $d->[0] if ref($d) eq "ARRAY"; - readingsSingleUpdate( $hash, "lastResponse", 'OK - Action: '. $commandCodes{$d->{commandId}}, 1 ) if defined $d->{commandId}; - readingsSingleUpdate( $hash, "lastResponse", 'ERROR: '. $d->{title}.' ('.$d->{status}.')', 1 ) if defined $d->{status} and defined $d->{title}; - return undef; - } else { - readingsSingleUpdate( $hash, "lastResponse", 'OK - empty', 1); - return undef; + if ( defined $decoded_json + and $decoded_json ne '' + and ref($decoded_json) eq "HASH" + or ( ref($decoded_json) eq "ARRAY" and $decoded_json > 0 ) ) + { + if ( $param->{dpoint} eq 'getChargers' ) { + Processing_DpointGetChargers( $hash, $decoded_json ); + return; } - }; + + if ( $param->{dpoint} eq 'getChargerSessionsDaily' ) { + Processing_DpointGetChargerSessionsDaily( $hash, $decoded_json ); + return; + } + + # Und so weiter und so weiter mit den einzelnen Funktionen !!! + + if ( $param->{dpoint} eq 'getChargerSessionsMonthly' ) { + Log3 $name, 5, 'Evaluating getChargerSessionsMonthly'; + my @x = $decoded_json; + my @a = ( -6 .. -1 ); + readingsBeginUpdate($hash); + for (@a) { + Log3 $name, 5, 'laeuft noch: ' . $_; + readingsBulkUpdate( + $hash, + "monthly_" . ( $_ + 1 ) . "_energy", + sprintf( + "%.2f", $decoded_json->[$_]->{'totalEnergyUsage'} + ) + ); + readingsBulkUpdate( + $hash, + "monthly_" . ( $_ + 1 ) . "_cost", + sprintf( "%.2f", $decoded_json->[$_]->{'totalCost'} ) + ); + } + readingsEndUpdate( $hash, 1 ); + return; + } + + if ( $param->{dpoint} eq 'getChargerConfiguration' ) { + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "isEnabled", + $decoded_json->{isEnabled} ); + readingsBulkUpdate( $hash, "isCablePermanentlyLocked", + $decoded_json->{lockCablePermanently} ); + readingsBulkUpdate( $hash, "isAuthorizationRequired", + $decoded_json->{authorizationRequired} ); + readingsBulkUpdate( $hash, "isRemoteStartRequired", + $decoded_json->{remoteStartRequired} ); + readingsBulkUpdate( $hash, "isSmartButtonEnabled", + $decoded_json->{smartButtonEnabled} ); + readingsBulkUpdate( $hash, "wiFiSSID", $decoded_json->{wiFiSSID} ); + readingsBulkUpdate( $hash, "phaseModeId", + $decoded_json->{phaseMode} ); + readingsBulkUpdate( $hash, "phaseMode", + $phaseModes{ $decoded_json->{phaseMode} } ); + readingsBulkUpdate( + $hash, + "isLocalAuthorizationRequired", + $decoded_json->{localAuthorizationRequired} + ); + readingsBulkUpdate( $hash, "maxChargerCurrent", + $decoded_json->{maxChargerCurrent} ); + readingsBulkUpdate( $hash, "ledStripBrightness", + $decoded_json->{ledStripBrightness} ); + + #readingsBulkUpdate( $hash, "charger_offlineChargingMode", + # $decoded_json->{offlineChargingMode} ); + #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP1", + # $decoded_json->{circuitMaxCurrentP1} ); + #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP2", + # $decoded_json->{circuitMaxCurrentP2} ); + #readingsBulkUpdate( $hash, "charger_circuitMaxCurrentP3", + # $decoded_json->{circuitMaxCurrentP3} ); + #readingsBulkUpdate( $hash, "charger_enableIdleCurrent", + # $decoded_json->{enableIdleCurrent} ); + #readingsBulkUpdate( + # $hash, + # "charger_limitToSinglePhaseCharging", + # $decoded_json->{limitToSinglePhaseCharging} + #); + + #readingsBulkUpdate( $hash, "charger_localNodeType", + # $decoded_json->{localNodeType} ); + + #readingsBulkUpdate( $hash, "charger_localRadioChannel", + # $decoded_json->{localRadioChannel} ); + #readingsBulkUpdate( $hash, "charger_localShortAddress", + # $decoded_json->{localShortAddress} ); + #readingsBulkUpdate( + # $hash, + # "charger_localParentAddrOrNumOfNodes", + # $decoded_json->{localParentAddrOrNumOfNodes} + #); + #readingsBulkUpdate( + # $hash, + # "charger_localPreAuthorizeEnabled", + # $decoded_json->{localPreAuthorizeEnabled} + #); + #readingsBulkUpdate( + # $hash, + # "charger_allowOfflineTxForUnknownId", + # $decoded_json->{allowOfflineTxForUnknownId} + #); + #readingsBulkUpdate( $hash, "chargingSchedule", + # $decoded_json->{chargingSchedule} ); + readingsBulkUpdate( $hash, "lastResponse", + 'OK - getChargerConfig', 1 ); + readingsEndUpdate( $hash, 1 ); + return; + } + + if ( $param->{dpoint} eq 'getCurrentSession' ) { + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "session_energy", + sprintf( "%.2f", $decoded_json->{sessionEnergy} ) ); + $value = + defined $decoded_json->{sessionStart} + ? _transcodeDate( $decoded_json->{sessionStart} ) + : 'N/A'; + readingsBulkUpdate( $hash, "session_start", $value ); + $value = + defined $decoded_json->{sessionEnd} + ? _transcodeDate( $decoded_json->{sessionEnd} ) + : 'N/A'; + readingsBulkUpdate( $hash, "session_end", $value ); + readingsBulkUpdate( + $hash, + "session_chargeDurationInSeconds", + $decoded_json->{chargeDurationInSeconds} + ); + $value = + defined $decoded_json->{firstEnergyTransferPeriodStart} + ? _transcodeDate( + $decoded_json->{firstEnergyTransferPeriodStart} ) + : 'N/A'; + readingsBulkUpdate( $hash, "session_firstEnergyTransfer", $value ); + $value = + defined $decoded_json->{lastEnergyTransferPeriodStart} + ? _transcodeDate( $decoded_json->{lastEnergyTransferPeriodStart} ) + : 'N/A'; + readingsBulkUpdate( $hash, "session_lastEnergyTransfer", $value ); + readingsBulkUpdate( $hash, "session_pricePerKWH", + $decoded_json->{pricePrKwhIncludingVat} ); + readingsBulkUpdate( $hash, "session_chargingCost", + sprintf( "%.2f", $decoded_json->{costIncludingVat} ) ); + readingsBulkUpdate( $hash, "session_id", + $decoded_json->{sessionId} ); + readingsBulkUpdate( $hash, "lastResponse", + 'OK - getCurrentSession', 1 ); + readingsEndUpdate( $hash, 1 ); + return; + } + + if ( $param->{dpoint} eq 'getChargerSite' ) { + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "cost_perKWh", + $decoded_json->{costPerKWh} ); + readingsBulkUpdate( $hash, "cost_perKwhExcludeVat", + $decoded_json->{costPerKwhExcludeVat} ); + readingsBulkUpdate( $hash, "cost_vat", $decoded_json->{vat} ); + readingsBulkUpdate( $hash, "cost_currency", + $decoded_json->{currencyId} ); + +#readingsBulkUpdate( $hash, "site_ratedCurrent", $decoded_json->{ratedCurrent} ); +#readingsBulkUpdate( $hash, "site_createdOn", $decoded_json->{createdOn} ); +#readingsBulkUpdate( $hash, "site_updatedOn", $decoded_json->{updatedOn} ); + readingsBulkUpdate( $hash, "lastResponse", + 'OK - getChargerSite', 1 ); + readingsEndUpdate( $hash, 1 ); + return; + } + + if ( $param->{dpoint} eq 'getChargerState' ) { + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "operationModeCode", + $decoded_json->{chargerOpMode} ); + readingsBulkUpdate( $hash, "operationMode", + $operationModes{ $decoded_json->{chargerOpMode} } ); + readingsBulkUpdate( $hash, "power", + sprintf( "%.2f", $decoded_json->{totalPower} ) ); + readingsBulkUpdate( $hash, "kWhInSession", + sprintf( "%.2f", $decoded_json->{sessionEnergy} ) ); + readingsBulkUpdate( $hash, "phase", $decoded_json->{outputPhase} ); + readingsBulkUpdate( $hash, "latestPulse", + _transcodeDate( $decoded_json->{latestPulse} ) ); + readingsBulkUpdate( $hash, "current", + $decoded_json->{outputCurrent} ); + readingsBulkUpdate( $hash, "dynamicCurrent", + $decoded_json->{dynamicChargerCurrent} ); + readingsBulkUpdate( $hash, "reasonCodeForNoCurrent", + $decoded_json->{reasonForNoCurrent} ); + readingsBulkUpdate( $hash, "reasonForNoCurrent", + $reasonsForNoCurrent{ $decoded_json->{reasonForNoCurrent} } ); + readingsBulkUpdate( $hash, "errorCode", + $decoded_json->{errorCode} ); + readingsBulkUpdate( $hash, "fatalErrorCode", + $decoded_json->{fatalErrorCode} ); + readingsBulkUpdate( $hash, "lifetimeEnergy", + sprintf( "%.2f", $decoded_json->{lifetimeEnergy} ) ); + readingsBulkUpdate( $hash, "online", $decoded_json->{isOnline} ); + readingsBulkUpdate( $hash, "voltage", + sprintf( "%.2f", $decoded_json->{voltage} ) ); + readingsBulkUpdate( $hash, "wifi_rssi", $decoded_json->{wiFiRSSI} ); + readingsBulkUpdate( $hash, "wifi_apEnabled", + $decoded_json->{wiFiAPEnabled} ); + readingsBulkUpdate( $hash, "cell_rssi", $decoded_json->{cellRSSI} ); + readingsBulkUpdate( $hash, "lastResponse", + 'OK - getChargerState', 1 ); + readingsEndUpdate( $hash, 1 ); + return; + } + + $decoded_json = $decoded_json->[0] if ref($decoded_json) eq "ARRAY"; + readingsSingleUpdate( $hash, "lastResponse", + 'OK - Action: ' . $commandCodes{ $decoded_json->{commandId} }, 1 ) + if defined $decoded_json->{commandId}; + readingsSingleUpdate( + $hash, + "lastResponse", + 'ERROR: ' + . $decoded_json->{title} . ' (' + . $decoded_json->{status} . ')', + 1 + ) + if defined $decoded_json->{status} and defined $decoded_json->{title}; + return; + } + else { + readingsSingleUpdate( $hash, "lastResponse", 'OK - empty', 1 ); + return; + } if ($@) { - readingsSingleUpdate( $hash, "lastResponse", 'ERROR while deconding response: '. $@, 1 ); + readingsSingleUpdate( $hash, "lastResponse", + 'ERROR while deconding response: ' . $@, 1 ); Log3 $name, 5, 'Failure decoding: ' . $@; - } + } return; } +sub Processing_DpointGetChargers { + my $hash = shift; + my $decoded_json = shift; + + my $site = $decoded_json->[0]; + my $circuit = $site->{circuits}->[0]; + my $charger = $circuit->{chargers}->[0]; + + readingsBeginUpdate($hash); + my $chargerId = $charger->{id}; + readingsBulkUpdate( $hash, "site_id", $site->{id} ); + readingsBulkUpdate( $hash, "site_key", $site->{siteKey} ); + readingsBulkUpdate( $hash, "charger_id", $chargerId ); + readingsBulkUpdate( $hash, "charger_name", $charger->{name} ); + readingsBulkUpdate( $hash, "lastResponse", 'OK - getReaders', 1 ); + readingsEndUpdate( $hash, 1 ); + + WriteToCloudAPI( $hash, 'getChargerConfiguration', 'GET' ); + + return; +} + +sub Processing_DpointGetChargerSessionsDaily { + my $hash = shift; + my $decoded_json = shift; + + my $name = $hash->{NAME}; + + Log3 $name, 5, 'Evaluating getChargerSessionsDaily'; + + my @x = $decoded_json; + my @a = ( -5 .. -1 ); + + readingsBeginUpdate($hash); + for (@a) { + Log3 $name, 5, 'laeuft noch: ' . $_; + readingsBulkUpdate( + $hash, + "daily_" . ( $_ + 1 ) . "_energy", + sprintf( "%.2f", $decoded_json->[$_]->{'totalEnergyUsage'} ) + ); + readingsBulkUpdate( + $hash, + "daily_" . ( $_ + 1 ) . "_cost", + sprintf( "%.2f", $decoded_json->[$_]->{'totalCost'} ) + ); + } + + readingsEndUpdate( $hash, 1 ); + + return; +} sub _loadToken { my $hash = shift; my $name = $hash->{NAME}; my $tokenLifeTime = $hash->{TOKEN_LIFETIME}; $tokenLifeTime = 0 if ( !defined $tokenLifeTime || $tokenLifeTime eq '' ); - my $Token = undef; + my $token; - $Token = $hash->{'.TOKEN'}; + $token = $hash->{'.TOKEN'}; if ( $@ || $tokenLifeTime < gettimeofday() ) { Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "Error while loading: $@ ,requesting new one" - if $@; + "EaseeWallbox $name" . ": " + . "Error while loading: $@ ,requesting new one" + if $@; Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "Token is expired, requesting new one" - if $tokenLifeTime < gettimeofday(); - $Token = _newTokenRequest($hash); + "EaseeWallbox $name" . ": " . "Token is expired, requesting new one" + if $tokenLifeTime < gettimeofday(); + $token = _newTokenRequest($hash); } else { Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "Token expires at " - . localtime($tokenLifeTime); + "EaseeWallbox $name" . ": " + . "Token expires at " + . localtime($tokenLifeTime); # if token is about to expire, refresh him if ( ( $tokenLifeTime - 3700 ) < gettimeofday() ) { Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "Token will expire soon, refreshing"; - $Token = _tokenRefresh($hash); + "EaseeWallbox $name" . ": " + . "Token will expire soon, refreshing"; + $token = _tokenRefresh($hash); } } - return $Token if $Token; + + $token = $token ? $token : undef; + return $token; } sub _newTokenRequest { - my $hash = shift; - my $name = $hash->{NAME}; - my $password - = _decrypt( InternalVal( $name, 'Password', undef ) ); + my $hash = shift; + my $name = $hash->{NAME}; + my $password = _decrypt( InternalVal( $name, 'Password', undef ) ); my $username = InternalVal( $name, 'Username', undef ); Log3 $name, 5, "EaseeWallbox $name" . ": " . "calling NewTokenRequest()"; @@ -948,17 +1059,17 @@ sub _newTokenRequest { if ( $err ne "" ) { Log3 $name, 3, - "EaseeWallbox $name" . ": " - . "NewTokenRequest: Error while requesting " - . $param->{url} - . " - $err"; + "EaseeWallbox $name" . ": " + . "NewTokenRequest: Error while requesting " + . $param->{url} + . " - $err"; } elsif ( $returnData ne "" ) { Log3 $name, 5, "url " . $param->{url} . " returned: $returnData"; my $decoded_data = eval { decode_json($returnData) }; if ($@) { Log3 $name, 3, "EaseeWallbox $name" . ": " - . "NewTokenRequest: decode_json failed, invalid json. error: $@ "; + . "NewTokenRequest: decode_json failed, invalid json. error: $@ "; } else { #write token data in hash @@ -968,15 +1079,17 @@ sub _newTokenRequest { # token lifetime management if ( defined($decoded_data) ) { - $hash->{TOKEN_LIFETIME} - = gettimeofday() + $decoded_data->{'expiresIn'}; + $hash->{TOKEN_LIFETIME} = + gettimeofday() + $decoded_data->{'expiresIn'}; } $hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} ); Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "Retrived new authentication token successfully. Valid until " - . localtime( $hash->{TOKEN_LIFETIME} ); - $hash->{STATE} = "reachable"; + "EaseeWallbox $name" . ": " + . "Retrived new authentication token successfully. Valid until " + . localtime( $hash->{TOKEN_LIFETIME} ); + +# $hash->{STATE} = "reachable"; # niemals $hash->{STATE} über demn Hash direkt zuweisen + readingsSingleUpdate( $hash, 'state', 'reachable', 1 ); return $decoded_data; } } @@ -1014,11 +1127,13 @@ sub _tokenRefresh { if ( $err ne "" ) { Log3 $name, 3, - "EaseeWallbox $name" . ": " - . "TokenRefresh: Error in token retrival while requesting " - . $param->{url} - . " - $err"; - $hash->{STATE} = "error"; + "EaseeWallbox $name" . ": " + . "TokenRefresh: Error in token retrival while requesting " + . $param->{url} + . " - $err"; + + # $hash->{STATE} = "error"; + readingsSingleUpdate( $hash, 'state', 'error', 1 ); } elsif ( $returnData ne "" ) { @@ -1027,10 +1142,12 @@ sub _tokenRefresh { if ($@) { Log3 $name, 3, - "EaseeWallbox $name" . ": " - . "TokenRefresh: decode_json failed, invalid json. error:$@\n" - if $@; - $hash->{STATE} = "error"; + "EaseeWallbox $name" . ": " + . "TokenRefresh: decode_json failed, invalid json. error:$@\n" + if $@; + + # $hash->{STATE} = "error"; + readingsSingleUpdate( $hash, 'state', 'error', 1 ); } else { #write token data in file @@ -1040,26 +1157,30 @@ sub _tokenRefresh { } # token lifetime management - $hash->{TOKEN_LIFETIME} - = gettimeofday() + $decoded_data->{'expires_in'}; + $hash->{TOKEN_LIFETIME} = + gettimeofday() + $decoded_data->{'expires_in'}; $hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} ); Log3 $name, 5, - "EaseeWallbox $name" . ": " - . "TokenRefresh: Refreshed authentication token successfully. Valid until " - . localtime( $hash->{TOKEN_LIFETIME} ); - $hash->{STATE} = "reachable"; + "EaseeWallbox $name" . ": " + . "TokenRefresh: Refreshed authentication token successfully. Valid until " + . localtime( $hash->{TOKEN_LIFETIME} ); + + # $hash->{STATE} = "reachable"; + readingsSingleUpdate( $hash, 'state', 'reachable', 1 ); return $decoded_data; } } return; } -sub _encrypt($) { +sub _encrypt { my ($decoded) = @_; my $key = getUniqueId(); my $encoded; - return $decoded if ( $decoded =~ /crypt:/ ); + return $decoded + if ( $decoded =~ /crypt:/x ) + ; # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) for my $char ( split //, $decoded ) { my $encode = chop($key); @@ -1070,16 +1191,21 @@ sub _encrypt($) { return 'crypt:' . $encoded; } -sub _decrypt($) { +sub _decrypt { my ($encoded) = @_; my $key = getUniqueId(); my $decoded; - return $encoded if ( $encoded !~ /crypt:/ ); + return $encoded + if ( $encoded !~ /crypt:/x ) + ; # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) - $encoded = $1 if ( $encoded =~ /crypt:(.*)/ ); + $encoded = $1 + if ( $encoded =~ /crypt:(.*)/x ) + ; # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) - for my $char ( map { pack( 'C', hex($_) ) } ( $encoded =~ /(..)/g ) ) { + for my $char ( map { pack( 'C', hex($_) ) } ( $encoded =~ /(..)/xg ) ) + { # Regular expression without "/x" flag. See page 236 of PBP (RegularExpressions::RequireExtendedFormatting) my $decode = chop($key); $decoded .= chr( ord($char) ^ ord($decode) ); $key = $decode . $key; @@ -1090,23 +1216,22 @@ sub _decrypt($) { 1; -sub _transcodeDate{ - my $datestr = shift; +sub _transcodeDate { + my $datestr = shift; Log3 'EaseeWallbox', 5, 'date to parse: ' . $datestr; - my $strp = DateTime::Format::Strptime->new(on_error=>'croak', - pattern => '%Y-%m-%dT%H:%M:%S%z'); + my $strp = DateTime::Format::Strptime->new( + on_error => 'croak', + pattern => '%Y-%m-%dT%H:%M:%S%z' + ); my $dt = $strp->parse_datetime($datestr); $dt->set_time_zone('Europe/Berlin'); + return $dt->strftime('%Y-%m-%d %H:%M:%S'); } - - +1; # Ein Modul muss immer mit 1; enden =pod =begin html - - =end html - =cut \ No newline at end of file