Merge branch 'devel' of git.tuxnet.lan:FHEM/mod-TeslaPowerwall2AC into devel

This commit is contained in:
Marko Oldenburg 2021-03-01 07:12:47 +01:00
commit f71e306954
3 changed files with 340 additions and 117 deletions

View File

@ -2,7 +2,7 @@
# #
# Developed with Kate # Developed with Kate
# #
# (c) 2017-2020 Copyright: Marko Oldenburg (leongaultier at gmail dot com) # (c) 2017-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved # All rights reserved
# #
# This script is free software; you can redistribute it and/or modify # This script is free software; you can redistribute it and/or modify
@ -144,6 +144,9 @@ BEGIN {
readingsBulkUpdateIfChanged readingsBulkUpdateIfChanged
readingsBeginUpdate readingsBeginUpdate
readingsEndUpdate readingsEndUpdate
setKeyValue
getKeyValue
getUniqueId
CommandAttr CommandAttr
defs defs
Log3 Log3
@ -170,56 +173,61 @@ GP_Export(
); );
my %paths = ( my %paths = (
'statussoe' => 'system_status/soe', 'statussoe' => 'system_status/soe',
'aggregates' => 'meters/aggregates', 'aggregates' => 'meters/aggregates',
'meterssite' => 'meters/site', 'meterssite' => 'meters/site',
'meterssolar' => 'meters/solar', 'meterssolar' => 'meters/solar',
'siteinfo' => 'site_info', 'siteinfo' => 'site_info',
'sitename' => 'site_info/site_name', 'sitename' => 'site_info/site_name',
'sitemaster' => 'sitemaster', 'sitemaster' => 'sitemaster',
'powerwalls' => 'powerwalls', 'powerwalls' => 'powerwalls',
'registration' => 'customer/registration', 'registration' => 'customer/registration',
'status' => 'status', 'status' => 'status',
'login' => 'login/Basic', 'gridstatus' => 'system_status/grid_status',
'gridstatus' => 'system_status/grid_status',
); );
my %cmdPaths = ( my %cmdPaths = (
'powerwallsstop' => 'sitemaster/stop', 'powerwallsstop' => 'sitemaster/stop',
'powerwallsrun' => 'sitemaster/run', 'powerwallsrun' => 'sitemaster/run',
); );
sub Initialize($) { sub Initialize {
my ($hash) = @_; my $hash = shift;
# Consumer # Consumer
$hash->{GetFn} = 'FHEM::TeslaPowerwall2AC::Get'; $hash->{GetFn} = \&Get;
$hash->{SetFn} = 'FHEM::TeslaPowerwall2AC::Set'; $hash->{SetFn} = \&Set;
$hash->{DefFn} = 'FHEM::TeslaPowerwall2AC::Define'; $hash->{DefFn} = \&Define;
$hash->{UndefFn} = 'FHEM::TeslaPowerwall2AC::Undef'; $hash->{UndefFn} = \&Undef;
$hash->{NotifyFn} = 'FHEM::TeslaPowerwall2AC::Notify'; $hash->{NotifyFn} = \&Notify;
$hash->{RenameFn} = \&Rename;
$hash->{AttrFn} = 'FHEM::TeslaPowerwall2AC::Attr'; $hash->{AttrFn} = \&Attr;
$hash->{AttrList} = $hash->{AttrList} =
'interval ' . 'disable:1 ' . 'devel:1 ' . $readingFnAttributes; 'interval '
. 'disable:1 '
. 'devel:1 '
. 'emailaddr '
. $readingFnAttributes;
$hash->{parseParams} = 1;
return FHEM::Meta::InitMod( __FILE__, $hash ); return FHEM::Meta::InitMod( __FILE__, $hash );
} }
sub Define($$) { sub Define {
my ( $hash, $def ) = @_; my $hash = shift // return;
my @a = split( '[ \t][ \t]*', $def ); my $aArg = shift // return;
return $@ unless ( FHEM::Meta::SetInternals($hash) ); return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
return 'too few parameters: define <name> TeslaPowerwall2AC <HOST>' return 'too few parameters: define <name> TeslaPowerwall2AC <HOST>'
if ( @a != 3 ); if ( scalar( @{$aArg} ) != 3 );
my $name = $a[0]; my $name = $aArg->[0];
my $host = $aArg->[2];
my $host = $a[2];
$hash->{HOST} = $host; $hash->{HOST} = $host;
$hash->{INTERVAL} = 300; $hash->{INTERVAL} = 300;
$hash->{VERSION} = version->parse($VERSION)->normal; $hash->{VERSION} = version->parse($VERSION)->normal;
@ -234,9 +242,9 @@ sub Define($$) {
return undef; return undef;
} }
sub Undef($$) { sub Undef {
my ( $hash, $arg ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $name = shift;
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
Log3 $name, 3, "TeslaPowerwall2AC ($name) - Device $name deleted"; Log3 $name, 3, "TeslaPowerwall2AC ($name) - Device $name deleted";
@ -244,7 +252,7 @@ sub Undef($$) {
return undef; return undef;
} }
sub Attr(@) { sub Attr {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
@ -289,7 +297,6 @@ sub Attr(@) {
$hash->{INTERVAL} = $attrVal; $hash->{INTERVAL} = $attrVal;
Log3 $name, 3, Log3 $name, 3,
"TeslaPowerwall2AC ($name) - set interval to $attrVal"; "TeslaPowerwall2AC ($name) - set interval to $attrVal";
Timer_GetData($hash);
} }
} }
elsif ( $cmd eq 'del' ) { elsif ( $cmd eq 'del' ) {
@ -297,16 +304,17 @@ sub Attr(@) {
$hash->{INTERVAL} = 300; $hash->{INTERVAL} = 300;
Log3 $name, 3, Log3 $name, 3,
"TeslaPowerwall2AC ($name) - set interval to default"; "TeslaPowerwall2AC ($name) - set interval to default";
Timer_GetData($hash);
} }
} }
return undef; return undef;
} }
sub Notify($$) { sub Notify {
my ( $hash, $dev ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $dev = shift;
my $name = $hash->{NAME};
return if ( IsDisabled($name) ); return if ( IsDisabled($name) );
my $devname = $dev->{NAME}; my $devname = $dev->{NAME};
@ -316,16 +324,24 @@ sub Notify($$) {
Timer_GetData($hash) Timer_GetData($hash)
if ( if (
grep /^INITIALIZED$/, ( grep /^INITIALIZED$/, @{$events}
@{$events} or grep /^DELETEATTR.$name.disable$/, or grep /^ATTR.$name.emailaddr$/, @{$events}
@{$events} or grep /^DELETEATTR.$name.interval$/, or grep /^ATTR.$name.interval$/, @{$events}
@{$events} or ( grep /^DEFINED.$name$/, @{$events} and $init_done ) or grep /^ATTR.$name.disable$/, @{$events}
or grep /^DELETEATTR.$name.disable$/, @{$events}
or grep /^DELETEATTR.$name.interval$/, @{$events}
or grep /^DEFINED.$name$/, @{$events} )
and $init_done
); );
return; return;
} }
sub Get($@) { sub Get {
my ( $hash, $name, $cmd ) = @_; my $hash = shift // return;
my $aArg = shift // return;
my $name = shift @$aArg;
my $cmd = shift @$aArg // return qq{"get $name" needs at least one argument};
my $arg; my $arg;
if ( $cmd eq 'statusSOE' ) { if ( $cmd eq 'statusSOE' ) {
@ -365,8 +381,12 @@ sub Get($@) {
} }
else { else {
my $list = my $list = '';
'statusSOE:noArg aggregates:noArg siteinfo:noArg sitemaster:noArg powerwalls:noArg registration:noArg status:noArg'; $list .=
'statusSOE:noArg aggregates:noArg siteinfo:noArg sitemaster:noArg powerwalls:noArg registration:noArg status:noArg'
if( AttrVal($name,'emailaddr','none') ne 'none'
&& defined(ReadPassword($hash, $name))
&& defined($hash->{TOKEN}) );
return 'Unknown argument ' . $cmd . ', choose one of ' . $list; return 'Unknown argument ' . $cmd . ', choose one of ' . $list;
} }
@ -381,16 +401,34 @@ sub Get($@) {
return undef; return undef;
} }
sub Set($@) { sub Set {
my ( $hash, $name, $cmd, @args ) = @_; my $hash = shift // return;
my $aArg = shift // return;
my $name = shift @$aArg;
my $cmd = shift @$aArg // return qq{"set $name" needs at least one argument};
my $arg; my $arg;
if ( $cmd eq 'powerwalls' ) { if ( $cmd eq 'powerwalls' ) {
$arg = lc( $cmd . $args[0] ); $arg = lc( $cmd . $aArg->[0] );
}
elsif ( lc $cmd eq 'setpassword' ) {
return "please set Attribut emailaddr first"
if ( AttrVal( $name, 'emailaddr', 'none' ) eq 'none' );
return "usage: $cmd <password>" if ( scalar( @{$aArg} ) != 1 );
StorePassword( $hash, $name, $aArg->[0] );
return Timer_GetData($hash);
}
elsif ( lc $cmd eq 'removepassword' ) {
return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 );
DeletePassword($hash);
return Timer_GetData($hash);
} }
else { else {
my $list = ''; my $list = ( defined(ReadPassword($hash, $name)) ? 'removePassword:noArg ' : 'setPassword ');
$list .= 'powerwalls:run,stop' $list .= 'powerwalls:run,stop'
if ( AttrVal( $name, 'devel', 0 ) == 1 ); if ( AttrVal( $name, 'devel', 0 ) == 1 );
@ -403,7 +441,7 @@ sub Set($@) {
return undef; return undef;
} }
sub Timer_GetData($) { sub Timer_GetData {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
@ -412,16 +450,27 @@ sub Timer_GetData($) {
if ( defined( $hash->{actionQueue} ) if ( defined( $hash->{actionQueue} )
and scalar( @{ $hash->{actionQueue} } ) == 0 ) and scalar( @{ $hash->{actionQueue} } ) == 0 )
{ {
if ( not IsDisabled($name) ) { if ( !IsDisabled($name) ) {
while ( my $obj = each %paths ) { return readingsSingleUpdate( $hash, 'state',
unshift( @{ $hash->{actionQueue} }, $obj ); 'please set Attribut emailaddr first', 1 )
if ( AttrVal( $name, 'emailaddr', 'none' ) eq 'none' );
return readingsSingleUpdate( $hash, 'state',
'please set password first', 1 )
if ( !defined( ReadPassword( $hash, $name ) ) );
if ( !defined( $hash->{TOKEN}) ) {
unshift( @{ $hash->{actionQueue} }, 'login' );
}
else {
while ( my $obj = each %paths ) {
unshift( @{ $hash->{actionQueue} }, $obj );
}
} }
Write($hash); Write($hash);
} }
else { else {
readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); return readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
} }
} }
@ -431,8 +480,8 @@ sub Timer_GetData($) {
"TeslaPowerwall2AC ($name) - Call InternalTimer Timer_GetData"; "TeslaPowerwall2AC ($name) - Call InternalTimer Timer_GetData";
} }
sub Write($) { sub Write {
my ($hash) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my ( $uri, $method, $header, $data, $path ) = my ( $uri, $method, $header, $data, $path ) =
@ -464,10 +513,13 @@ sub Write($) {
Log3 $name, 4, "TeslaPowerwall2AC ($name) - Send with URI: https://$uri"; Log3 $name, 4, "TeslaPowerwall2AC ($name) - Send with URI: https://$uri";
} }
sub ErrorHandling($$$) { sub ErrorHandling {
my ( $param, $err, $data ) = @_; my $param = shift;
my $hash = $param->{hash}; my $err = shift;
my $name = $hash->{NAME}; my $data = shift;
my $hash = $param->{hash};
my $name = $hash->{NAME};
### Begin Error Handling ### Begin Error Handling
@ -538,9 +590,12 @@ sub ErrorHandling($$$) {
ResponseProcessing( $hash, $param->{setCmd}, $data ); ResponseProcessing( $hash, $param->{setCmd}, $data );
} }
sub ResponseProcessing($$$) { sub ResponseProcessing {
my ( $hash, $path, $json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $path = shift;
my $json = shift;
my $name = $hash->{NAME};
my $decode_json; my $decode_json;
my $readings; my $readings;
@ -570,7 +625,8 @@ sub ResponseProcessing($$$) {
$readings = ReadingsProcessing_Powerwalls( $hash, $decode_json ); $readings = ReadingsProcessing_Powerwalls( $hash, $decode_json );
} }
elsif ( $path eq 'login' ) { elsif ( $path eq 'login' ) {
return $hash->{TOKEN} = $decode_json->{token}; $hash->{TOKEN} = $decode_json->{token};
return Timer_GetData($hash);
} }
elsif ( $path eq 'meterssite' ) { elsif ( $path eq 'meterssite' ) {
$readings = ReadingsProcessing_Meters_Site( $hash, $decode_json ); $readings = ReadingsProcessing_Meters_Site( $hash, $decode_json );
@ -585,9 +641,12 @@ sub ResponseProcessing($$$) {
WriteReadings( $hash, $path, $readings ); WriteReadings( $hash, $path, $readings );
} }
sub WriteReadings($$$) { sub WriteReadings {
my ( $hash, $path, $readings ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $path = shift;
my $readings = shift;
my $name = $hash->{NAME};
Log3 $name, 4, "TeslaPowerwall2AC ($name) - Write Readings"; Log3 $name, 4, "TeslaPowerwall2AC ($name) - Write Readings";
@ -610,6 +669,7 @@ sub WriteReadings($$$) {
) * ReadingsVal( $name, 'statussoe-percentage', 0 ) ) * ReadingsVal( $name, 'statussoe-percentage', 0 )
) )
); );
readingsBulkUpdateIfChanged( $hash, 'actionQueue', readingsBulkUpdateIfChanged( $hash, 'actionQueue',
scalar( @{ $hash->{actionQueue} } ) . ' entries in the Queue' ); scalar( @{ $hash->{actionQueue} } ) . ' entries in the Queue' );
readingsBulkUpdateIfChanged( readingsBulkUpdateIfChanged(
@ -623,12 +683,15 @@ sub WriteReadings($$$) {
. ' paths in actionQueue' . ' paths in actionQueue'
) )
); );
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
} }
sub ReadingsProcessing_Aggregates($$) { sub ReadingsProcessing_Aggregates {
my ( $hash, $decode_json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $decode_json = shift;
my $name = $hash->{NAME};
my %readings; my %readings;
if ( ref($decode_json) eq 'HASH' ) { if ( ref($decode_json) eq 'HASH' ) {
@ -645,20 +708,37 @@ sub ReadingsProcessing_Aggregates($$) {
return \%readings; return \%readings;
} }
sub ReadingsProcessing_Powerwalls($$) { sub ReadingsProcessing_Powerwalls {
my ( $hash, $decode_json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $decode_json = shift;
my $name = $hash->{NAME};
my %readings; my %readings;
if ( ref( $decode_json->{powerwalls} ) eq 'ARRAY' if ( ref( $decode_json->{powerwalls} ) eq 'ARRAY'
and scalar( @{ $decode_json->{powerwalls} } ) > 0 ) && scalar( @{ $decode_json->{powerwalls} } ) > 0 )
{ {
my $i = 0; my $i = 0;
foreach my $powerwall ( @{ $decode_json->{powerwalls} } ) { for my $powerwall ( @{ $decode_json->{powerwalls} } ) {
if ( ref($powerwall) eq 'HASH' ) { if ( ref($powerwall) eq 'HASH' ) {
while ( my ( $r, $v ) = each %{$powerwall} ) { while ( my ( $r, $v ) = each %{$powerwall} ) {
$readings{ 'wall_' . $i . '_' . $r } = $v; $readings{ 'wall_' . $i . '_' . $r } = $v
if ( ref($v) ne 'HASH' );
if ( ref($v) eq 'HASH' ) {
while ( my ( $s, $ts ) = each %{$v} ) {
if ( ref( $ts ) eq 'ARRAY'
&& scalar( @{ $ts } ) > 0 )
{
my $j = 0;
for my $t ( @{ $ts } ) {
$readings{ 'wall_' . $i . '_' . $r . '_' . $s . '_' . $j } = $t;
$j++;
}
}
}
}
} }
$i++; $i++;
@ -674,9 +754,11 @@ sub ReadingsProcessing_Powerwalls($$) {
return \%readings; return \%readings;
} }
sub ReadingsProcessing_Site_Info($$) { sub ReadingsProcessing_Site_Info {
my ( $hash, $decode_json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $decode_json = shift;
my $name = $hash->{NAME};
my %readings; my %readings;
if ( ref($decode_json) eq 'HASH' ) { if ( ref($decode_json) eq 'HASH' ) {
@ -693,9 +775,11 @@ sub ReadingsProcessing_Site_Info($$) {
return \%readings; return \%readings;
} }
sub ReadingsProcessing_Meters_Site($$) { sub ReadingsProcessing_Meters_Site {
my ( $hash, $decode_json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $decode_json = shift;
my $name = $hash->{NAME};
my %readings; my %readings;
if ( ref($decode_json) eq 'ARRAY' if ( ref($decode_json) eq 'ARRAY'
@ -704,7 +788,7 @@ sub ReadingsProcessing_Meters_Site($$) {
if ( ref( $decode_json->[0] ) eq 'HASH' ) { if ( ref( $decode_json->[0] ) eq 'HASH' ) {
while ( my $obj = each %{ $decode_json->[0] } ) { while ( my $obj = each %{ $decode_json->[0] } ) {
if ( ref( $decode_json->[0]->{$obj} ) eq 'ARRAY' if ( ref( $decode_json->[0]->{$obj} ) eq 'ARRAY'
or ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) || ref( $decode_json->[0]->{$obj} ) eq 'HASH' )
{ {
if ( ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) { if ( ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) {
while ( my ( $r, $v ) = while ( my ( $r, $v ) =
@ -740,9 +824,11 @@ sub ReadingsProcessing_Meters_Site($$) {
return \%readings; return \%readings;
} }
sub ReadingsProcessing_Meters_Solar($$) { sub ReadingsProcessing_Meters_Solar {
my ( $hash, $decode_json ) = @_; my $hash = shift;
my $name = $hash->{NAME}; my $decode_json = shift;
my $name = $hash->{NAME};
my %readings; my %readings;
if ( ref($decode_json) eq 'ARRAY' if ( ref($decode_json) eq 'ARRAY'
@ -751,7 +837,7 @@ sub ReadingsProcessing_Meters_Solar($$) {
if ( ref( $decode_json->[0] ) eq 'HASH' ) { if ( ref( $decode_json->[0] ) eq 'HASH' ) {
while ( my $obj = each %{ $decode_json->[0] } ) { while ( my $obj = each %{ $decode_json->[0] } ) {
if ( ref( $decode_json->[0]->{$obj} ) eq 'ARRAY' if ( ref( $decode_json->[0]->{$obj} ) eq 'ARRAY'
or ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) || ref( $decode_json->[0]->{$obj} ) eq 'HASH' )
{ {
if ( ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) { if ( ref( $decode_json->[0]->{$obj} ) eq 'HASH' ) {
while ( my ( $r, $v ) = while ( my ( $r, $v ) =
@ -787,39 +873,135 @@ sub ReadingsProcessing_Meters_Solar($$) {
return \%readings; return \%readings;
} }
sub CreateUri($$) { sub CreateUri {
my ( $hash, $path ) = @_; my $hash = shift;
my $host = $hash->{HOST}; my $path = shift;
my $method = 'GET';
my $uri; my $name = $hash->{NAME};
my $header; my $host = $hash->{HOST};
my $header = ( defined($hash->{TOKEN}) ? 'Cookie: AuthCookie=' . $hash->{TOKEN} : undef );
my $method = 'GET';
my $uri = ( $path ne 'login' ? $host . '/api/' . $paths{$path} : $host . '/api/login/Basic' );
my $data; my $data;
if ( $path eq 'powerwallsstop'
or $path eq 'powerwallsruns' ) if ( $path eq 'login' ) {
$method = 'POST';
$header = 'Content-Type: application/json';
$data =
'{"username":"customer","password":"'
. ReadPassword( $hash, $name )
. '","email":"'
. AttrVal($name,'emailaddr','test@test.de')
. '","force_sm_off":false}'
}
elsif ( $path eq 'powerwallsstop'
|| $path eq 'powerwallsruns' )
{ {
$uri = $host . '/api/' . $cmdPaths{$path}; $uri = $host . '/api/' . $cmdPaths{$path};
}
else {
$uri = $host . '/api/' . $paths{$path};
}
if ( $path eq 'sitemasterrun' ) {
$header = 'Authorization: Bearer' . $hash->{TOKEN};
}
elsif ( $path eq 'login' ) {
$method = 'POST';
$header = 'Content-Type: application/json';
$data = '{"username":"","password":"S'
. ReadingsVal( $hash->{NAME},
'powerwalls-wall_0_PackageSerialNumber', 0 )
. '","force_sm_off":false}';
} }
return ( $uri, $method, $header, $data, $path ); return ( $uri, $method, $header, $data, $path );
} }
sub StorePassword {
my $hash = shift;
my $name = shift;
my $password = shift;
my $index = $hash->{TYPE} . "_" . $name . "_passwd";
my $key = getUniqueId() . $index;
my $enc_pwd = "";
if ( eval "use Digest::MD5;1" ) {
$key = Digest::MD5::md5_hex( unpack "H*", $key );
$key .= Digest::MD5::md5_hex($key);
}
for my $char ( split //, $password ) {
my $encode = chop($key);
$enc_pwd .= sprintf( "%.2x", ord($char) ^ ord($encode) );
$key = $encode . $key;
}
my $err = setKeyValue( $index, $enc_pwd );
return "error while saving the password - $err" if ( defined($err) );
return "password successfully saved";
}
sub ReadPassword {
my $hash = shift;
my $name = shift;
my $index = $hash->{TYPE} . "_" . $name . "_passwd";
my $key = getUniqueId() . $index;
my ( $password, $err );
Log3 $name, 4, "TeslaPowerwall2AC ($name) - Read password from file";
( $err, $password ) = getKeyValue($index);
if ( defined($err) ) {
Log3 $name, 3,
"TeslaPowerwall2AC ($name) - unable to read password from file: $err";
return undef;
}
if ( defined($password) ) {
if ( eval "use Digest::MD5;1" ) {
$key = Digest::MD5::md5_hex( unpack "H*", $key );
$key .= Digest::MD5::md5_hex($key);
}
my $dec_pwd = '';
for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/g ) ) {
my $decode = chop($key);
$dec_pwd .= chr( ord($char) ^ ord($decode) );
$key = $decode . $key;
}
return $dec_pwd;
}
else {
Log3 $name, 3, "TeslaPowerwall2AC ($name) - No password in file";
return undef;
}
return;
}
sub DeletePassword {
my $hash = shift;
setKeyValue( $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd", undef );
return;
}
sub Rename {
my $new = shift;
my $old = shift;
my $hash = $defs{$new};
StorePassword( $hash, $new, ReadPassword( $hash, $old ) );
setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef );
return;
}
1; 1;
=pod =pod
@ -865,6 +1047,8 @@ sub CreateUri($$) {
<li>state - information about internel modul processes</li> <li>state - information about internel modul processes</li>
<li>status-* - readings of the /api/status response</li> <li>status-* - readings of the /api/status response</li>
<li>statussoe-* - readings of the /api/system_status/soe response</li> <li>statussoe-* - readings of the /api/system_status/soe response</li>
<li>setPassword - write password encrypted to password file</li>
<li>removePassword - remove password from password file</li>
</ul> </ul>
<a name="TeslaPowerwall2ACget"></a> <a name="TeslaPowerwall2ACget"></a>
<b>get</b> <b>get</b>
@ -881,6 +1065,7 @@ sub CreateUri($$) {
<b>Attribute</b> <b>Attribute</b>
<ul> <ul>
<li>interval - interval in seconds for automatically fetch data (default 300)</li> <li>interval - interval in seconds for automatically fetch data (default 300)</li>
<li>emailaddr - emailadress to get cookie token</li>
</ul> </ul>
</ul> </ul>
@ -909,9 +1094,9 @@ sub CreateUri($$) {
"Powerwall", "Powerwall",
"Control" "Control"
], ],
"release_status": "under develop", "release_status": "stable",
"license": "GPL_2", "license": "GPL_2",
"version": "v0.8.0", "version": "v1.0.2",
"author": [ "author": [
"Marko Oldenburg <leongaultier@gmail.com>" "Marko Oldenburg <leongaultier@gmail.com>"
], ],

View File

@ -0,0 +1 @@
UPD 2021-02-27_17:20:40 31370 FHEM/46_TeslaPowerwall2AC.pm

37
hooks/pre-commit Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/perl -w
use File::Basename;
use POSIX qw(strftime);
use strict;
my @filenames = ('FHEM/46_TeslaPowerwall2AC.pm');
my $controlsfile = 'controls_TeslaPowerwall2AC.txt';
open(FH, ">$controlsfile") || return("Can't open $controlsfile: $!");
for my $filename (@filenames) {
my @statOutput = stat($filename);
if (scalar @statOutput != 13) {
printf 'error: stat has unexpected return value for ' . $filename . "\n";
next;
}
my $mtime = $statOutput[9];
my $date = POSIX::strftime("%Y-%m-%d", localtime($mtime));
my $time = POSIX::strftime("%H:%M:%S", localtime($mtime));
my $filetime = $date."_".$time;
my $filesize = $statOutput[7];
printf FH 'UPD ' . $filetime . ' ' . $filesize . ' ' .$filename . "\n";
}
close(FH);
system("git add $controlsfile");
print 'Create controls File succesfully' . "\n";
exit 0;