From f734d0e0719776fd13fa4202013dcffd7ff9485f Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 04:44:16 +0100 Subject: [PATCH 01/11] code cleaning and new code style change login method --- 46_TeslaPowerwall2AC.pm | 209 +++++++++++++++++++-------------- controls_TeslaPowerwall2AC.txt | 0 hooks/pre-commit | 37 ++++++ 3 files changed, 156 insertions(+), 90 deletions(-) create mode 100644 controls_TeslaPowerwall2AC.txt create mode 100755 hooks/pre-commit diff --git a/46_TeslaPowerwall2AC.pm b/46_TeslaPowerwall2AC.pm index 6b30dd7..bbaee30 100644 --- a/46_TeslaPowerwall2AC.pm +++ b/46_TeslaPowerwall2AC.pm @@ -2,7 +2,7 @@ # # Developed with Kate # -# (c) 2017-2019 Copyright: Marko Oldenburg (leongaultier at gmail dot com) +# (c) 2017-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) # All rights reserved # # This script is free software; you can redistribute it and/or modify @@ -170,28 +170,27 @@ GP_Export( ); my %paths = ( - 'statussoe' => 'system_status/soe', - 'aggregates' => 'meters/aggregates', - 'meterssite' => 'meters/site', - 'meterssolar' => 'meters/solar', - 'siteinfo' => 'site_info', - 'sitename' => 'site_info/site_name', - 'sitemaster' => 'sitemaster', - 'powerwalls' => 'powerwalls', - 'registration' => 'customer/registration', - 'status' => 'status', - 'login' => 'login/Basic', - 'gridstatus' => 'system_status/grid_status', + 'statussoe' => 'system_status/soe', + 'aggregates' => 'meters/aggregates', + 'meterssite' => 'meters/site', + 'meterssolar' => 'meters/solar', + 'siteinfo' => 'site_info', + 'sitename' => 'site_info/site_name', + 'sitemaster' => 'sitemaster', + 'powerwalls' => 'powerwalls', + 'registration' => 'customer/registration', + 'status' => 'status', + 'gridstatus' => 'system_status/grid_status', ); my %cmdPaths = ( - 'powerwallsstop' => 'sitemaster/stop', - 'powerwallsrun' => 'sitemaster/run', + 'powerwallsstop' => 'sitemaster/stop', + 'powerwallsrun' => 'sitemaster/run', ); -sub Initialize($) { +sub Initialize { - my ($hash) = @_; + my $hash = shift; # Consumer $hash->{GetFn} = 'FHEM::TeslaPowerwall2AC::Get'; @@ -207,9 +206,11 @@ sub Initialize($) { return FHEM::Meta::InitMod( __FILE__, $hash ); } -sub Define($$) { - my ( $hash, $def ) = @_; - my @a = split( '[ \t][ \t]*', $def ); +sub Define { + my $hash = shift; + my $def = shift; + + my @a = split( '[ \t][ \t]*', $def ); return $@ unless ( FHEM::Meta::SetInternals($hash) ); use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); @@ -234,9 +235,11 @@ sub Define($$) { return undef; } -sub Undef($$) { - my ( $hash, $arg ) = @_; - my $name = $hash->{NAME}; +sub Undef { + my $hash = shift; + my $arg = shift; + + my $name = $hash->{NAME}; RemoveInternalTimer($hash); Log3 $name, 3, "TeslaPowerwall2AC ($name) - Device $name deleted"; @@ -244,7 +247,7 @@ sub Undef($$) { return undef; } -sub Attr(@) { +sub Attr { my ( $cmd, $name, $attrName, $attrVal ) = @_; my $hash = $defs{$name}; @@ -304,9 +307,11 @@ sub Attr(@) { return undef; } -sub Notify($$) { - my ( $hash, $dev ) = @_; - my $name = $hash->{NAME}; +sub Notify { + my $hash = shift; + my $dev = shift; + + my $name = $hash->{NAME}; return if ( IsDisabled($name) ); my $devname = $dev->{NAME}; @@ -324,8 +329,10 @@ sub Notify($$) { return; } -sub Get($@) { - my ( $hash, $name, $cmd ) = @_; +sub Get { + my $hash = shift; + my $name = shift; + my $cmd = shift; my $arg; if ( $cmd eq 'statusSOE' ) { @@ -381,7 +388,7 @@ sub Get($@) { return undef; } -sub Set($@) { +sub Set { my ( $hash, $name, $cmd, @args ) = @_; my $arg; @@ -403,7 +410,7 @@ sub Set($@) { return undef; } -sub Timer_GetData($) { +sub Timer_GetData { my $hash = shift; my $name = $hash->{NAME}; @@ -413,12 +420,16 @@ sub Timer_GetData($) { and scalar( @{ $hash->{actionQueue} } ) == 0 ) { if ( not IsDisabled($name) ) { - while ( my $obj = each %paths ) { - unshift( @{ $hash->{actionQueue} }, $obj ); + if ( !defined( $hash->{TOKEN}) ) { + unshift( @{ $hash->{actionQueue} }, 'login' ); + } + else { + while ( my $obj = each %paths ) { + unshift( @{ $hash->{actionQueue} }, $obj ); + } } Write($hash); - } else { readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); @@ -431,8 +442,8 @@ sub Timer_GetData($) { "TeslaPowerwall2AC ($name) - Call InternalTimer Timer_GetData"; } -sub Write($) { - my ($hash) = @_; +sub Write { + my $hash = shift; my $name = $hash->{NAME}; my ( $uri, $method, $header, $data, $path ) = @@ -464,10 +475,13 @@ sub Write($) { Log3 $name, 4, "TeslaPowerwall2AC ($name) - Send with URI: https://$uri"; } -sub ErrorHandling($$$) { - my ( $param, $err, $data ) = @_; - my $hash = $param->{hash}; - my $name = $hash->{NAME}; +sub ErrorHandling { + my $param = shift; + my $err = shift; + my $data = shift; + + my $hash = $param->{hash}; + my $name = $hash->{NAME}; ### Begin Error Handling @@ -538,9 +552,12 @@ sub ErrorHandling($$$) { ResponseProcessing( $hash, $param->{setCmd}, $data ); } -sub ResponseProcessing($$$) { - my ( $hash, $path, $json ) = @_; - my $name = $hash->{NAME}; +sub ResponseProcessing { + my $hash = shift; + my $path = shift; + my $json = shift; + + my $name = $hash->{NAME}; my $decode_json; my $readings; @@ -570,7 +587,8 @@ sub ResponseProcessing($$$) { $readings = ReadingsProcessing_Powerwalls( $hash, $decode_json ); } elsif ( $path eq 'login' ) { - return $hash->{TOKEN} = $decode_json->{token}; + $hash->{TOKEN} = $decode_json->{token}; + return Timer_GetData($hash); } elsif ( $path eq 'meterssite' ) { $readings = ReadingsProcessing_Meters_Site( $hash, $decode_json ); @@ -585,9 +603,12 @@ sub ResponseProcessing($$$) { WriteReadings( $hash, $path, $readings ); } -sub WriteReadings($$$) { - my ( $hash, $path, $readings ) = @_; - my $name = $hash->{NAME}; +sub WriteReadings { + my $hash = shift; + my $path = shift; + my $readings = shift; + + my $name = $hash->{NAME}; Log3 $name, 4, "TeslaPowerwall2AC ($name) - Write Readings"; @@ -610,6 +631,7 @@ sub WriteReadings($$$) { ) * ReadingsVal( $name, 'statussoe-percentage', 0 ) ) ); + readingsBulkUpdateIfChanged( $hash, 'actionQueue', scalar( @{ $hash->{actionQueue} } ) . ' entries in the Queue' ); readingsBulkUpdateIfChanged( @@ -623,12 +645,15 @@ sub WriteReadings($$$) { . ' paths in actionQueue' ) ); + readingsEndUpdate( $hash, 1 ); } -sub ReadingsProcessing_Aggregates($$) { - my ( $hash, $decode_json ) = @_; - my $name = $hash->{NAME}; +sub ReadingsProcessing_Aggregates { + my $hash = shift; + my $decode_json = shift; + + my $name = $hash->{NAME}; my %readings; if ( ref($decode_json) eq 'HASH' ) { @@ -645,9 +670,11 @@ sub ReadingsProcessing_Aggregates($$) { return \%readings; } -sub ReadingsProcessing_Powerwalls($$) { - my ( $hash, $decode_json ) = @_; - my $name = $hash->{NAME}; +sub ReadingsProcessing_Powerwalls { + my $hash = shift; + my $decode_json = shift; + + my $name = $hash->{NAME}; my %readings; if ( ref( $decode_json->{powerwalls} ) eq 'ARRAY' @@ -674,9 +701,11 @@ sub ReadingsProcessing_Powerwalls($$) { return \%readings; } -sub ReadingsProcessing_Site_Info($$) { - my ( $hash, $decode_json ) = @_; - my $name = $hash->{NAME}; +sub ReadingsProcessing_Site_Info { + my $hash = shift; + my $decode_json = shift; + + my $name = $hash->{NAME}; my %readings; if ( ref($decode_json) eq 'HASH' ) { @@ -693,9 +722,11 @@ sub ReadingsProcessing_Site_Info($$) { return \%readings; } -sub ReadingsProcessing_Meters_Site($$) { - my ( $hash, $decode_json ) = @_; - my $name = $hash->{NAME}; +sub ReadingsProcessing_Meters_Site { + my $hash = shift; + my $decode_json = shift; + + my $name = $hash->{NAME}; my %readings; if ( ref($decode_json) eq 'ARRAY' @@ -704,7 +735,7 @@ sub ReadingsProcessing_Meters_Site($$) { if ( ref( $decode_json->[0] ) eq 'HASH' ) { while ( my $obj = each %{ $decode_json->[0] } ) { 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' ) { while ( my ( $r, $v ) = @@ -740,9 +771,11 @@ sub ReadingsProcessing_Meters_Site($$) { return \%readings; } -sub ReadingsProcessing_Meters_Solar($$) { - my ( $hash, $decode_json ) = @_; - my $name = $hash->{NAME}; +sub ReadingsProcessing_Meters_Solar { + my $hash = shift; + my $decode_json = shift; + + my $name = $hash->{NAME}; my %readings; if ( ref($decode_json) eq 'ARRAY' @@ -751,7 +784,7 @@ sub ReadingsProcessing_Meters_Solar($$) { if ( ref( $decode_json->[0] ) eq 'HASH' ) { while ( my $obj = each %{ $decode_json->[0] } ) { 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' ) { while ( my ( $r, $v ) = @@ -787,34 +820,30 @@ sub ReadingsProcessing_Meters_Solar($$) { return \%readings; } -sub CreateUri($$) { - my ( $hash, $path ) = @_; - my $host = $hash->{HOST}; - my $method = 'GET'; - my $uri; - my $header; +sub CreateUri { + my $hash = shift; + my $path = shift; + + my $host = $hash->{HOST}; + my $header = ( defined($hash->{TOKEN}) ? 'Cookie: AuthCookie=' . $hash->{TOKEN} : undef ); + my $method = 'GET'; + my $uri = ( defined($paths{$path}) ? $host . '/api/' . $paths{$path} : undef ); my $data; - if ( $path eq 'powerwallsstop' - or $path eq 'powerwallsruns' ) + + if ( $path eq 'login' ) { + $method = 'POST'; + $header = 'Content-Type: application/json'; + $uri = 'login/Basic', + $data = '{"username":"","password":"S' + . ReadingsVal( $hash->{NAME}, + 'powerwalls-wall_0_PackageSerialNumber', 0 ) + . '","force_sm_off":false}'; + } + elsif ( $path eq 'powerwallsstop' + || $path eq 'powerwallsruns' ) { - $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}'; + $uri = $host . '/api/' . $cmdPaths{$path}; } return ( $uri, $method, $header, $data, $path ); @@ -911,7 +940,7 @@ sub CreateUri($$) { ], "release_status": "under develop", "license": "GPL_2", - "version": "v0.7.3", + "version": "v0.7.99", "author": [ "Marko Oldenburg " ], diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt new file mode 100644 index 0000000..e69de29 diff --git a/hooks/pre-commit b/hooks/pre-commit new file mode 100755 index 0000000..10fc0dd --- /dev/null +++ b/hooks/pre-commit @@ -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; From 7a1c51959e1962e2259638abc267b6ac0c7b8366 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 04:55:59 +0100 Subject: [PATCH 02/11] change control file --- hooks/pre-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/pre-commit b/hooks/pre-commit index 10fc0dd..6baad04 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -4,7 +4,7 @@ use File::Basename; use POSIX qw(strftime); use strict; -my @filenames = ( 'FHEM/46_TeslaPowerwall2AC.pm'); +my @filenames = ('FHEM/46_TeslaPowerwall2AC.pm',); my $controlsfile = 'controls_TeslaPowerwall2AC.txt'; From 1b3fb852b65232c4acbb4960f08d1c4e3c99ce37 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 05:17:23 +0100 Subject: [PATCH 03/11] change directory structure --- 46_TeslaPowerwall2AC.pm => FHEM/46_TeslaPowerwall2AC.pm | 0 controls_TeslaPowerwall2AC.txt | 1 + hooks/pre-commit | 6 +++--- 3 files changed, 4 insertions(+), 3 deletions(-) rename 46_TeslaPowerwall2AC.pm => FHEM/46_TeslaPowerwall2AC.pm (100%) diff --git a/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm similarity index 100% rename from 46_TeslaPowerwall2AC.pm rename to FHEM/46_TeslaPowerwall2AC.pm diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index e69de29..dd4b8ff 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -0,0 +1 @@ +UPD 2021-02-27_04:38:01 26844 FHEM/46_TeslaPowerwall2AC.pm diff --git a/hooks/pre-commit b/hooks/pre-commit index 6baad04..5ae86ea 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -4,15 +4,15 @@ use File::Basename; use POSIX qw(strftime); use strict; -my @filenames = ('FHEM/46_TeslaPowerwall2AC.pm',); +my @filenames = ('FHEM/46_TeslaPowerwall2AC.pm'); -my $controlsfile = 'controls_TeslaPowerwall2AC.txt'; +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; From 0d36ac89577559325ea1d17941632711a80471f3 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 12:12:42 +0100 Subject: [PATCH 04/11] add email and password fn --- FHEM/46_TeslaPowerwall2AC.pm | 215 +++++++++++++++++++++++++++------ controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 178 insertions(+), 39 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index bbaee30..9bda73d 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -144,6 +144,9 @@ BEGIN { readingsBulkUpdateIfChanged readingsBeginUpdate readingsEndUpdate + setKeyValue + getKeyValue + getUniqueId CommandAttr defs Log3 @@ -193,34 +196,38 @@ sub Initialize { my $hash = shift; # Consumer - $hash->{GetFn} = 'FHEM::TeslaPowerwall2AC::Get'; - $hash->{SetFn} = 'FHEM::TeslaPowerwall2AC::Set'; - $hash->{DefFn} = 'FHEM::TeslaPowerwall2AC::Define'; - $hash->{UndefFn} = 'FHEM::TeslaPowerwall2AC::Undef'; - $hash->{NotifyFn} = 'FHEM::TeslaPowerwall2AC::Notify'; + $hash->{GetFn} = \&Get; + $hash->{SetFn} = \&Set; + $hash->{DefFn} = \&Define; + $hash->{UndefFn} = \&Undef; + $hash->{NotifyFn} = \&Notify; + $hash->{RenameFn} = \&Rename; - $hash->{AttrFn} = 'FHEM::TeslaPowerwall2AC::Attr'; + $hash->{AttrFn} = \&Attr; $hash->{AttrList} = - 'interval ' . 'disable:1 ' . 'devel:1 ' . $readingFnAttributes; + 'interval ' + . 'disable:1 ' + . 'devel:1 ' + . 'emailaddr ' + . $readingFnAttributes; + $hash->{parseParams} = 1; return FHEM::Meta::InitMod( __FILE__, $hash ); } sub Define { - my $hash = shift; - my $def = shift; - - my @a = split( '[ \t][ \t]*', $def ); + my $hash = shift // return; + my $aArg = shift // return; return $@ unless ( FHEM::Meta::SetInternals($hash) ); use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); return 'too few parameters: define TeslaPowerwall2AC ' - 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->{INTERVAL} = 300; $hash->{VERSION} = version->parse($VERSION)->normal; @@ -237,9 +244,7 @@ sub Define { sub Undef { my $hash = shift; - my $arg = shift; - - my $name = $hash->{NAME}; + my $name = shift; RemoveInternalTimer($hash); Log3 $name, 3, "TeslaPowerwall2AC ($name) - Device $name deleted"; @@ -292,7 +297,6 @@ sub Attr { $hash->{INTERVAL} = $attrVal; Log3 $name, 3, "TeslaPowerwall2AC ($name) - set interval to $attrVal"; - Timer_GetData($hash); } } elsif ( $cmd eq 'del' ) { @@ -300,7 +304,6 @@ sub Attr { $hash->{INTERVAL} = 300; Log3 $name, 3, "TeslaPowerwall2AC ($name) - set interval to default"; - Timer_GetData($hash); } } @@ -321,18 +324,24 @@ sub Notify { Timer_GetData($hash) if ( - grep /^INITIALIZED$/, - @{$events} or grep /^DELETEATTR.$name.disable$/, - @{$events} or grep /^DELETEATTR.$name.interval$/, - @{$events} or ( grep /^DEFINED.$name$/, @{$events} and $init_done ) + ( grep /^INITIALIZED$/, @{$events} + or grep /^ATTR.$name.emailaddr$/, @{$events} + or grep /^ATTR.$name.interval$/, @{$events} + 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; } sub Get { - my $hash = shift; - my $name = shift; - my $cmd = shift; + 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; if ( $cmd eq 'statusSOE' ) { @@ -372,8 +381,11 @@ sub Get { } else { - my $list = -'statusSOE:noArg aggregates:noArg siteinfo:noArg sitemaster:noArg powerwalls:noArg registration:noArg status:noArg'; + my $list = ''; + $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)) ); return 'Unknown argument ' . $cmd . ', choose one of ' . $list; } @@ -389,15 +401,33 @@ sub Get { } 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; 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 " 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 { - my $list = ''; + my $list = ( defined(ReadPassword($hash, $name)) ? 'removePassword:noArg ' : 'setPassword '); $list .= 'powerwalls:run,stop' if ( AttrVal( $name, 'devel', 0 ) == 1 ); @@ -419,7 +449,14 @@ sub Timer_GetData { if ( defined( $hash->{actionQueue} ) and scalar( @{ $hash->{actionQueue} } ) == 0 ) { - if ( not IsDisabled($name) ) { + if ( !IsDisabled($name) ) { + return readingsSingleUpdate( $hash, 'state', + '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' ); } @@ -432,7 +469,7 @@ sub Timer_GetData { Write($hash); } else { - readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); + return readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); } } @@ -824,10 +861,11 @@ sub CreateUri { my $hash = shift; my $path = shift; + my $name = $hash->{NAME}; my $host = $hash->{HOST}; my $header = ( defined($hash->{TOKEN}) ? 'Cookie: AuthCookie=' . $hash->{TOKEN} : undef ); my $method = 'GET'; - my $uri = ( defined($paths{$path}) ? $host . '/api/' . $paths{$path} : undef ); + my $uri = ( $path ne 'login' ? $host . '/api/' . $paths{$path} : undef ); my $data; @@ -835,10 +873,10 @@ sub CreateUri { $method = 'POST'; $header = 'Content-Type: application/json'; $uri = 'login/Basic', - $data = '{"username":"","password":"S' - . ReadingsVal( $hash->{NAME}, - 'powerwalls-wall_0_PackageSerialNumber', 0 ) - . '","force_sm_off":false}'; + $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' ) @@ -849,6 +887,104 @@ sub CreateUri { 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; =pod @@ -894,6 +1030,8 @@ sub CreateUri {
  • state - information about internel modul processes
  • status-* - readings of the /api/status response
  • statussoe-* - readings of the /api/system_status/soe response
  • +
  • setPassword - write password encrypted to password file
  • +
  • removePassword - remove password from password file
  • get @@ -910,6 +1048,7 @@ sub CreateUri { Attribute
    • interval - interval in seconds for automatically fetch data (default 300)
    • +
    • emailaddr - emailadress to get cookie token
    diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index dd4b8ff..d0ee2cd 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_04:38:01 26844 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_12:10:30 30701 FHEM/46_TeslaPowerwall2AC.pm From 3757e5e281719ed7a9954cf8248c97a894997c0d Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 14:08:04 +0100 Subject: [PATCH 05/11] fix compose uri in CreateUri Fn --- FHEM/46_TeslaPowerwall2AC.pm | 16 +++++++++------- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index 9bda73d..476e881 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -385,7 +385,8 @@ sub Get { $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(ReadPassword($hash, $name)) + && defined($hash->{TOKEN}) ); return 'Unknown argument ' . $cmd . ', choose one of ' . $list; } @@ -865,18 +866,19 @@ sub CreateUri { 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} : undef ); + my $uri = ( $path ne 'login' ? $host . '/api/' . $paths{$path} : $host . '/api/login/Basic' ); my $data; if ( $path eq 'login' ) { $method = 'POST'; $header = 'Content-Type: application/json'; - $uri = 'login/Basic', - $data = '{"username":"customer","password":"' . ReadPassword( $hash, $name ) . '","email":"' . AttrVal($name,'emailaddr','test@test.de') . '","force_sm_off":false}' - - - + $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' ) diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index d0ee2cd..70c3db9 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_12:10:30 30701 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_14:06:51 30728 FHEM/46_TeslaPowerwall2AC.pm From f723f1efaf7229175fceebf5e8918bb1dda89a2b Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 14:57:59 +0100 Subject: [PATCH 06/11] change version --- FHEM/46_TeslaPowerwall2AC.pm | 4 ++-- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index 476e881..55381ce 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -1079,9 +1079,9 @@ sub Rename { "Powerwall", "Control" ], - "release_status": "under develop", + "release_status": "stable", "license": "GPL_2", - "version": "v0.7.99", + "version": "v1.0.0", "author": [ "Marko Oldenburg " ], diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index 70c3db9..2695dc7 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_14:06:51 30728 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_14:54:29 30720 FHEM/46_TeslaPowerwall2AC.pm From a4ddfe9c8a5492c2af6b792e7b4047174a73cf65 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 15:28:08 +0100 Subject: [PATCH 07/11] change foreach to for --- FHEM/46_TeslaPowerwall2AC.pm | 2 +- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index 55381ce..d6e2f10 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -719,7 +719,7 @@ sub ReadingsProcessing_Powerwalls { and scalar( @{ $decode_json->{powerwalls} } ) > 0 ) { my $i = 0; - foreach my $powerwall ( @{ $decode_json->{powerwalls} } ) { + for my $powerwall ( @{ $decode_json->{powerwalls} } ) { if ( ref($powerwall) eq 'HASH' ) { while ( my ( $r, $v ) = each %{$powerwall} ) { diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index 2695dc7..ec57af1 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_14:54:29 30720 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_15:27:28 30716 FHEM/46_TeslaPowerwall2AC.pm From b4dde90ae9be5de65397effb20f9100d3d23897d Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 15:42:17 +0100 Subject: [PATCH 08/11] add more readings --- FHEM/46_TeslaPowerwall2AC.pm | 6 ++++++ controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index d6e2f10..cbbf3b4 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -724,6 +724,12 @@ sub ReadingsProcessing_Powerwalls { while ( my ( $r, $v ) = each %{$powerwall} ) { $readings{ 'wall_' . $i . '_' . $r } = $v; + + if ref($v) eq 'HASH' ) { + while ( my ( $s, $t ) = each %{$v} ) { + $readings{ 'wall_' . $i . '_' . $r . '_' . $s } = $t; + } + } } $i++; diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index ec57af1..0cd9cb0 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_15:27:28 30716 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_15:42:04 30955 FHEM/46_TeslaPowerwall2AC.pm From ed2b5f531d2413354cbd512a22351ba5262c017d Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 15:48:43 +0100 Subject: [PATCH 09/11] fix crash --- FHEM/46_TeslaPowerwall2AC.pm | 2 +- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index cbbf3b4..ec4577d 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -725,7 +725,7 @@ sub ReadingsProcessing_Powerwalls { while ( my ( $r, $v ) = each %{$powerwall} ) { $readings{ 'wall_' . $i . '_' . $r } = $v; - if ref($v) eq 'HASH' ) { + if ( ref($v) eq 'HASH' ) { while ( my ( $s, $t ) = each %{$v} ) { $readings{ 'wall_' . $i . '_' . $r . '_' . $s } = $t; } diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index 0cd9cb0..578a684 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_15:42:04 30955 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_15:47:38 30957 FHEM/46_TeslaPowerwall2AC.pm From cdc37dd24c2a36e9176781c80646c0f2c542ec10 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 16:41:31 +0100 Subject: [PATCH 10/11] fix hash in reading --- FHEM/46_TeslaPowerwall2AC.pm | 5 +++-- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index ec4577d..366cdd4 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -723,7 +723,8 @@ sub ReadingsProcessing_Powerwalls { if ( ref($powerwall) eq 'HASH' ) { 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, $t ) = each %{$v} ) { @@ -1087,7 +1088,7 @@ sub Rename { ], "release_status": "stable", "license": "GPL_2", - "version": "v1.0.0", + "version": "v1.0.1", "author": [ "Marko Oldenburg " ], diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index 578a684..6ffa09c 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_15:47:38 30957 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_16:41:15 31004 FHEM/46_TeslaPowerwall2AC.pm From 861c786d52510834e3eaf3aa9c33eab7c5c984c8 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Sat, 27 Feb 2021 17:21:48 +0100 Subject: [PATCH 11/11] expand ARRAYs --- FHEM/46_TeslaPowerwall2AC.pm | 16 ++++++++++++---- controls_TeslaPowerwall2AC.txt | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/FHEM/46_TeslaPowerwall2AC.pm b/FHEM/46_TeslaPowerwall2AC.pm index 366cdd4..b04fdf1 100644 --- a/FHEM/46_TeslaPowerwall2AC.pm +++ b/FHEM/46_TeslaPowerwall2AC.pm @@ -716,7 +716,7 @@ sub ReadingsProcessing_Powerwalls { my %readings; if ( ref( $decode_json->{powerwalls} ) eq 'ARRAY' - and scalar( @{ $decode_json->{powerwalls} } ) > 0 ) + && scalar( @{ $decode_json->{powerwalls} } ) > 0 ) { my $i = 0; for my $powerwall ( @{ $decode_json->{powerwalls} } ) { @@ -727,8 +727,16 @@ sub ReadingsProcessing_Powerwalls { if ( ref($v) ne 'HASH' ); if ( ref($v) eq 'HASH' ) { - while ( my ( $s, $t ) = each %{$v} ) { - $readings{ 'wall_' . $i . '_' . $r . '_' . $s } = $t; + 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++; + } + } } } } @@ -1088,7 +1096,7 @@ sub Rename { ], "release_status": "stable", "license": "GPL_2", - "version": "v1.0.1", + "version": "v1.0.2", "author": [ "Marko Oldenburg " ], diff --git a/controls_TeslaPowerwall2AC.txt b/controls_TeslaPowerwall2AC.txt index 6ffa09c..68baf0d 100644 --- a/controls_TeslaPowerwall2AC.txt +++ b/controls_TeslaPowerwall2AC.txt @@ -1 +1 @@ -UPD 2021-02-27_16:41:15 31004 FHEM/46_TeslaPowerwall2AC.pm +UPD 2021-02-27_17:20:40 31370 FHEM/46_TeslaPowerwall2AC.pm