added second half of the script. Issue of patch was the regex containing # which must be escaped in regex extended

This commit is contained in:
Matthias Sandmann 2022-03-26 23:20:30 +01:00
parent fc6e74dd3c
commit d3a1ed9fbd

View File

@ -1,7 +1,5 @@
package FHEM::EaseeWallbox; package FHEM::EaseeWallbox;
# use GPUtils qw(GP_Import GP_Export); hast Du auch weiter unten stehen
use strict; use strict;
use warnings; use warnings;
use Data::Dumper; use Data::Dumper;
@ -70,9 +68,7 @@ eval {
# Import von Funktionen und/oder Variablen aus der FHEM main # Import von Funktionen und/oder Variablen aus der FHEM main
# man kann ::Funktionaname wählen und sich so den Import schenken. Variablen sollten aber # man kann ::Funktionaname wählen und sich so den Import schenken. Variablen sollten aber
# sauber importiert werden # sauber importiert werden
# use GPUtils qw(GP_Import); use GPUtils qw(GP_Import GP_Export);
use GPUtils qw(GP_Import GP_Export)
; # da Du beide Funktionen aus dem package verwendest
## Import der FHEM Funktionen ## Import der FHEM Funktionen
#-- Run before package compilation #-- Run before package compilation
@ -230,9 +226,6 @@ my %commandCodes = (
); );
#Private function to evaluate command-lists #Private function to evaluate command-lists
# private funktionen beginnen immer mit _
#############################
sub _GetCmdList { sub _GetCmdList {
my ( $hash, $cmd, $commands ) = @_; my ( $hash, $cmd, $commands ) = @_;
@ -265,13 +258,7 @@ sub _GetCmdList {
if ( !defined($retVal) ) { if ( !defined($retVal) ) {
return "error while parsing set-table"; return "error while parsing set-table";
} }
return "Unknown argument $cmd, choose one of " . $retVal; 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 { sub Initialize {
@ -302,11 +289,8 @@ sub Define {
# set API URI as Internal Key # set API URI as Internal Key
$hash->{APIURI} = 'https://api.easee.cloud/api/'; $hash->{APIURI} = 'https://api.easee.cloud/api/';
Log3 $name, 3, "EaseeWallbox_Define $name: called "; Log3 $name, 3, "EaseeWallbox_Define $name: called ";
my $errmsg = ''; 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 ) { if ( int(@param) < 4 ) {
$errmsg = return $errmsg = return
@ -582,36 +566,42 @@ sub WriteToCloudAPI {
my $deviceId = "WC1"; my $deviceId = "WC1";
if ( not defined $hash ) { if ( not defined $hash ) {
my $msg = "Error on EaseeWallbox_WriteToCloudAPI. Missing hash variable"; my $msg =
"Error on EaseeWallbox_WriteToCloudAPI. Missing hash variable";
Log3 'EaseeWallbox', 1, $msg; Log3 'EaseeWallbox', 1, $msg;
return $msg; return $msg;
} }
#Check if chargerID is required in URL and replace or alert. #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 ); my $chargerId = ReadingsVal( $name, 'charger_id', undef );
if ( not defined $chargerId ) { 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; Log3 'EaseeWallbox', 1, $error;
return $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. #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 ); my $siteId = ReadingsVal( $name, 'site_id', undef );
if ( not defined $siteId ) { 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; Log3 'EaseeWallbox', 1, $error;
return $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 $CurrentTokenData = _loadToken($hash);
my $header = my $header = {
{
"Content-Type" => "application/json;charset=UTF-8", "Content-Type" => "application/json;charset=UTF-8",
"Authorization" => "Authorization" =>
"$CurrentTokenData->{'tokenType'} $CurrentTokenData->{'accessToken'}" "$CurrentTokenData->{'tokenType'} $CurrentTokenData->{'accessToken'}"
@ -648,13 +638,17 @@ sub ResponseHandling {
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 ); readingsSingleUpdate( $hash, "lastResponse", "ERROR $err", 1 );
return undef; return;
} }
my $code = $param->{code}; my $code = $param->{code};
if ($code eq 404 and $param->{dpoint} eq 'getCurrentSession'){ 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_energy' );
readingsDelete( $hash, 'session_start' ); readingsDelete( $hash, 'session_start' );
readingsDelete( $hash, 'session_end' ); readingsDelete( $hash, 'session_end' );
@ -664,13 +658,17 @@ sub ResponseHandling {
readingsDelete( $hash, 'session_pricePerKWH' ); readingsDelete( $hash, 'session_pricePerKWH' );
readingsDelete( $hash, 'session_chargingCost' ); readingsDelete( $hash, 'session_chargingCost' );
readingsDelete( $hash, 'session_id' ); readingsDelete( $hash, 'session_id' );
return undef; return;
} }
if ( $code >= 400 ) { if ( $code >= 400 ) {
Log3 $name, 3,"HTTPS error while requesting ". $param->{url}. " - $code"; # Eintrag fürs Log Log3 $name, 3,
readingsSingleUpdate( $hash, "lastResponse", "ERROR: HTTP Code $code", 1 ); "HTTPS error while requesting "
return undef; . $param->{url}
. " - $code"; # Eintrag fürs Log
readingsSingleUpdate( $hash, "lastResponse", "ERROR: HTTP Code $code",
1 );
return;
} }
Log3 $name, 3, Log3 $name, 3,
@ -685,16 +683,267 @@ sub ResponseHandling {
Log3 $name, 2, "Something gone wrong" Log3 $name, 2, "Something gone wrong"
if ( $data =~ "/EaseeWallboxMode/" ); if ( $data =~ "/EaseeWallboxMode/" );
my $d; my $decoded_json;
eval {
my $d = decode_json($data);
Log3 $name, 5, 'Decoded: ' . Dumper($d);
Log3 $name, 5, 'Ref of d: ' . ref($d);
if ( defined $d and $d ne '' and ref($d) eq "HASH" or (ref($d) eq "ARRAY" and $d gt 0)) { eval { $decoded_json = decode_json($data) }; # statt eval ist es empfohlen catch try zu verwenden. Machen wir später
if($param->{dpoint} eq 'getChargers') if ($@) {
Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request";
}
Log3 $name, 5, 'Decoded: ' . Dumper($decoded_json);
Log3 $name, 5, 'Ref of d: ' . ref($decoded_json);
my $value;
if ( defined $decoded_json
and $decoded_json ne ''
and ref($decoded_json) eq "HASH"
or ( ref($decoded_json) eq "ARRAY" and $decoded_json > 0 ) )
{ {
my $site = $d->[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 );
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 $circuit = $site->{circuits}->[0];
my $charger = $circuit->{chargers}->[0]; my $charger = $circuit->{chargers}->[0];
@ -706,189 +955,51 @@ sub ResponseHandling {
readingsBulkUpdate( $hash, "charger_name", $charger->{name} ); readingsBulkUpdate( $hash, "charger_name", $charger->{name} );
readingsBulkUpdate( $hash, "lastResponse", 'OK - getReaders', 1 ); readingsBulkUpdate( $hash, "lastResponse", 'OK - getReaders', 1 );
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
WriteToCloudAPI( $hash, 'getChargerConfiguration', 'GET' ); WriteToCloudAPI( $hash, 'getChargerConfiguration', 'GET' );
return; return;
} }
if($param->{dpoint} eq 'getChargerSessionsDaily') sub Processing_DpointGetChargerSessionsDaily {
{ my $hash = shift;
my $decoded_json = shift;
my $name = $hash->{NAME};
Log3 $name, 5, 'Evaluating getChargerSessionsDaily'; Log3 $name, 5, 'Evaluating getChargerSessionsDaily';
my @x = $d;
my @x = $decoded_json;
my @a = ( -5 .. -1 ); my @a = ( -5 .. -1 );
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
for (@a) { for (@a) {
Log3 $name, 5, 'laeuft noch: ' . $_; Log3 $name, 5, 'laeuft noch: ' . $_;
readingsBulkUpdate( $hash, "daily_".($_ +1)."_energy", sprintf("%.2f",$d->[$_]->{'totalEnergyUsage'}) ); readingsBulkUpdate(
readingsBulkUpdate( $hash, "daily_".($_ +1)."_cost", sprintf("%.2f",$d->[$_]->{'totalCost'}) ); $hash,
"daily_" . ( $_ + 1 ) . "_energy",
sprintf( "%.2f", $decoded_json->[$_]->{'totalEnergyUsage'} )
);
readingsBulkUpdate(
$hash,
"daily_" . ( $_ + 1 ) . "_cost",
sprintf( "%.2f", $decoded_json->[$_]->{'totalCost'} )
);
} }
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
return;
}
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;
}
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 ($@) {
readingsSingleUpdate( $hash, "lastResponse", 'ERROR while deconding response: '. $@, 1 );
Log3 $name, 5, 'Failure decoding: ' . $@;
}
return; return;
} }
sub _loadToken { sub _loadToken {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $tokenLifeTime = $hash->{TOKEN_LIFETIME}; my $tokenLifeTime = $hash->{TOKEN_LIFETIME};
$tokenLifeTime = 0 if ( !defined $tokenLifeTime || $tokenLifeTime eq '' ); $tokenLifeTime = 0 if ( !defined $tokenLifeTime || $tokenLifeTime eq '' );
my $Token = undef; my $token;
$Token = $hash->{'.TOKEN'}; $token = $hash->{'.TOKEN'};
if ( $@ || $tokenLifeTime < gettimeofday() ) { if ( $@ || $tokenLifeTime < gettimeofday() ) {
Log3 $name, 5, Log3 $name, 5,
@ -896,10 +1007,9 @@ sub _loadToken {
. "Error while loading: $@ ,requesting new one" . "Error while loading: $@ ,requesting new one"
if $@; if $@;
Log3 $name, 5, Log3 $name, 5,
"EaseeWallbox $name" . ": " "EaseeWallbox $name" . ": " . "Token is expired, requesting new one"
. "Token is expired, requesting new one"
if $tokenLifeTime < gettimeofday(); if $tokenLifeTime < gettimeofday();
$Token = _newTokenRequest($hash); $token = _newTokenRequest($hash);
} }
else { else {
Log3 $name, 5, Log3 $name, 5,
@ -912,17 +1022,18 @@ sub _loadToken {
Log3 $name, 5, Log3 $name, 5,
"EaseeWallbox $name" . ": " "EaseeWallbox $name" . ": "
. "Token will expire soon, refreshing"; . "Token will expire soon, refreshing";
$Token = _tokenRefresh($hash); $token = _tokenRefresh($hash);
} }
} }
return $Token if $Token;
$token = $token ? $token : undef;
return $token;
} }
sub _newTokenRequest { sub _newTokenRequest {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $password my $password = _decrypt( InternalVal( $name, 'Password', undef ) );
= _decrypt( InternalVal( $name, 'Password', undef ) );
my $username = InternalVal( $name, 'Username', undef ); my $username = InternalVal( $name, 'Username', undef );
Log3 $name, 5, "EaseeWallbox $name" . ": " . "calling NewTokenRequest()"; Log3 $name, 5, "EaseeWallbox $name" . ": " . "calling NewTokenRequest()";
@ -968,15 +1079,17 @@ sub _newTokenRequest {
# token lifetime management # token lifetime management
if ( defined($decoded_data) ) { if ( defined($decoded_data) ) {
$hash->{TOKEN_LIFETIME} $hash->{TOKEN_LIFETIME} =
= gettimeofday() + $decoded_data->{'expiresIn'}; gettimeofday() + $decoded_data->{'expiresIn'};
} }
$hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} ); $hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} );
Log3 $name, 5, Log3 $name, 5,
"EaseeWallbox $name" . ": " "EaseeWallbox $name" . ": "
. "Retrived new authentication token successfully. Valid until " . "Retrived new authentication token successfully. Valid until "
. localtime( $hash->{TOKEN_LIFETIME} ); . localtime( $hash->{TOKEN_LIFETIME} );
$hash->{STATE} = "reachable";
# $hash->{STATE} = "reachable"; # niemals $hash->{STATE} über demn Hash direkt zuweisen
readingsSingleUpdate( $hash, 'state', 'reachable', 1 );
return $decoded_data; return $decoded_data;
} }
} }
@ -1018,7 +1131,9 @@ sub _tokenRefresh {
. "TokenRefresh: Error in token retrival while requesting " . "TokenRefresh: Error in token retrival while requesting "
. $param->{url} . $param->{url}
. " - $err"; . " - $err";
$hash->{STATE} = "error";
# $hash->{STATE} = "error";
readingsSingleUpdate( $hash, 'state', 'error', 1 );
} }
elsif ( $returnData ne "" ) { elsif ( $returnData ne "" ) {
@ -1030,7 +1145,9 @@ sub _tokenRefresh {
"EaseeWallbox $name" . ": " "EaseeWallbox $name" . ": "
. "TokenRefresh: decode_json failed, invalid json. error:$@\n" . "TokenRefresh: decode_json failed, invalid json. error:$@\n"
if $@; if $@;
$hash->{STATE} = "error";
# $hash->{STATE} = "error";
readingsSingleUpdate( $hash, 'state', 'error', 1 );
} }
else { else {
#write token data in file #write token data in file
@ -1040,26 +1157,30 @@ sub _tokenRefresh {
} }
# token lifetime management # token lifetime management
$hash->{TOKEN_LIFETIME} $hash->{TOKEN_LIFETIME} =
= gettimeofday() + $decoded_data->{'expires_in'}; gettimeofday() + $decoded_data->{'expires_in'};
$hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} ); $hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} );
Log3 $name, 5, Log3 $name, 5,
"EaseeWallbox $name" . ": " "EaseeWallbox $name" . ": "
. "TokenRefresh: Refreshed authentication token successfully. Valid until " . "TokenRefresh: Refreshed authentication token successfully. Valid until "
. localtime( $hash->{TOKEN_LIFETIME} ); . localtime( $hash->{TOKEN_LIFETIME} );
$hash->{STATE} = "reachable";
# $hash->{STATE} = "reachable";
readingsSingleUpdate( $hash, 'state', 'reachable', 1 );
return $decoded_data; return $decoded_data;
} }
} }
return; return;
} }
sub _encrypt($) { sub _encrypt {
my ($decoded) = @_; my ($decoded) = @_;
my $key = getUniqueId(); my $key = getUniqueId();
my $encoded; 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 ) { for my $char ( split //, $decoded ) {
my $encode = chop($key); my $encode = chop($key);
@ -1070,16 +1191,21 @@ sub _encrypt($) {
return 'crypt:' . $encoded; return 'crypt:' . $encoded;
} }
sub _decrypt($) { sub _decrypt {
my ($encoded) = @_; my ($encoded) = @_;
my $key = getUniqueId(); my $key = getUniqueId();
my $decoded; 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); my $decode = chop($key);
$decoded .= chr( ord($char) ^ ord($decode) ); $decoded .= chr( ord($char) ^ ord($decode) );
$key = $decode . $key; $key = $decode . $key;
@ -1093,20 +1219,19 @@ sub _decrypt($) {
sub _transcodeDate { sub _transcodeDate {
my $datestr = shift; my $datestr = shift;
Log3 'EaseeWallbox', 5, 'date to parse: ' . $datestr; Log3 'EaseeWallbox', 5, 'date to parse: ' . $datestr;
my $strp = DateTime::Format::Strptime->new(on_error=>'croak', my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%dT%H:%M:%S%z'); on_error => 'croak',
pattern => '%Y-%m-%dT%H:%M:%S%z'
);
my $dt = $strp->parse_datetime($datestr); my $dt = $strp->parse_datetime($datestr);
$dt->set_time_zone('Europe/Berlin'); $dt->set_time_zone('Europe/Berlin');
return $dt->strftime('%Y-%m-%d %H:%M:%S'); return $dt->strftime('%Y-%m-%d %H:%M:%S');
} }
1; # Ein Modul muss immer mit 1; enden
=pod =pod
=begin html =begin html
=end html =end html
=cut =cut