98_powerMap: refactoring get-devices; improved support for 3rd party module integration

git-svn-id: https://svn.fhem.de/fhem/trunk@13171 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
loredo
2017-01-21 18:51:53 +00:00
parent ce0aa2aa6a
commit c9f7248f99

View File

@@ -25,8 +25,6 @@
# #
################################################################################ ################################################################################
# TODO # TODO
# - help users setting powerMap attribute using internal hash database or
# by copying from $defs{$name}{powerMap}
# - document how to include powerMap for other module maintainers # - document how to include powerMap for other module maintainers
# (see 50_HP1000) # (see 50_HP1000)
# #
@@ -47,9 +45,9 @@ sub powerMap_Attr(@);
sub powerMap_Notify($$); sub powerMap_Notify($$);
sub powerMap_AttrVal($$$$); sub powerMap_AttrVal($$$$);
sub powerMap_load($$;$); sub powerMap_load($$;$$);
sub powerMap_unload($$); sub powerMap_unload($$);
sub powerMap_FindPowerMaps(;$); sub powerMap_findPowerMaps(;$);
sub powerMap_power($$$;$); sub powerMap_power($$$;$);
sub powerMap_energy($$;$); sub powerMap_energy($$;$);
sub powerMap_update($;$); sub powerMap_update($;$);
@@ -588,7 +586,7 @@ sub powerMap_Set($@) {
my $value = join( " ", @a ) if (@a); my $value = join( " ", @a ) if (@a);
my $assign; my $assign;
my $maps = powerMap_FindPowerMaps(); my $maps = powerMap_findPowerMaps();
foreach ( sort keys %{$maps} ) { foreach ( sort keys %{$maps} ) {
$assign .= "," if ($assign); $assign .= "," if ($assign);
$assign .= $_; $assign .= $_;
@@ -602,14 +600,7 @@ sub powerMap_Set($@) {
my $ret; my $ret;
if ( $argument eq "devices" ) { if ( $argument eq "assign" ) {
my @devices = devspec2array("$TYPE=.+");
return @devices
? join( "\n", sort(@devices) )
: "no devices with $TYPE attribute defined";
}
elsif ( $argument eq "assign" ) {
my @devices = devspec2array($value); my @devices = devspec2array($value);
return "No matching device found." unless (@devices); return "No matching device found." unless (@devices);
@@ -659,14 +650,16 @@ sub powerMap_Get($@) {
. join( " ", values %powerMap_gets ) . join( " ", values %powerMap_gets )
unless ( exists( $powerMap_gets{$argument} ) ); unless ( exists( $powerMap_gets{$argument} ) );
my $ret;
if ( $argument eq "devices" ) { if ( $argument eq "devices" ) {
my @devices = devspec2array("i:$TYPE=.+"); my $pmdevs = powerMap_findPowerMaps(":PM_ENABLED");
return @devices return keys %{$pmdevs}
? join( "\n", sort(@devices) ) ? join( "\n", sort keys %{$pmdevs} )
: "no devices with $TYPE attribute defined"; : "No powerMap enabled devices found.";
} }
return; return $ret;
} }
sub powerMap_Attr(@) { sub powerMap_Attr(@) {
@@ -722,43 +715,21 @@ sub powerMap_Notify($$) {
foreach my $event ( @{$events} ) { foreach my $event ( @{$events} ) {
next unless ( defined($event) ); next unless ( defined($event) );
if ( $event =~ m/^(INITIALIZED|SHUTDOWN)$/ ) { # initialize or terminate powerMap for each device
my $event_prefix = $1; if ( $event =~ /^(INITIALIZED|SHUTDOWN)$/ ) {
foreach ( keys %{ powerMap_findPowerMaps(":PM_$1") } ) {
# search for devices with user defined
# powerMap support to be initialized
my @slaves =
devspec2array( "a:$TYPE=.+:FILTER=$TYPE" . "_noEnergy!=1" );
# search for loaded modules with direct
# powerMap support to be initialized
foreach ( keys %modules ) {
if ( defined( $modules{$_}{$TYPE} ) ) {
my @instances =
devspec2array(
"a:TYPE=$_:FILTER=$TYPE" . "_noEnergy!=1" );
push @slaves, @instances;
}
}
# search for devices with direct
# powerMap support to be initialized
foreach ( keys %defs ) {
push( @slaves, $_ )
if ( defined( $defs{$_}{$TYPE} ) );
}
# remove duplicates
my %h = map { $_ => 1 } @slaves;
@slaves = keys %h;
# initialize or terminate powerMap for each device
foreach (@slaves) {
next if ( $_ eq "global" or $_ eq $name );
next next
unless ( $event_prefix eq "SHUTDOWN" if ( $_ eq "global"
or powerMap_load( $name, $_ ) ); or $_ eq $name
Log3 $name, 4, "$TYPE: $event_prefix for $_"; or
powerMap_AttrVal( $name, $_, $TYPE . "_noEnergy", 0 ) );
powerMap_update("$name|$dev") if ( $1 eq "SHUTDOWN" );
next
unless ( $1 eq "SHUTDOWN"
|| powerMap_load( $name, $_, undef, 1 ) );
Log3 $name, 4, "$TYPE: $1 for $_";
} }
} }
@@ -896,8 +867,8 @@ sub powerMap_AttrVal($$$$) {
return AttrVal( $p, $TYPE . "_" . $n, AttrVal( $p, $n, $default ) ); return AttrVal( $p, $TYPE . "_" . $n, AttrVal( $p, $n, $default ) );
} }
sub powerMap_load($$;$) { sub powerMap_load($$;$$) {
my ( $name, $dev, $unload ) = @_; my ( $name, $dev, $unload, $modSupport ) = @_;
my $dev_hash = $defs{$dev}; my $dev_hash = $defs{$dev};
my $TYPE = $defs{$name}{TYPE}; my $TYPE = $defs{$name}{TYPE};
@@ -954,8 +925,7 @@ sub powerMap_load($$;$) {
unless ($powerMap) { unless ($powerMap) {
return powerMap_update("$name|$dev") return powerMap_update("$name|$dev")
if ( defined( $dev_hash->{$TYPE}{map} ) if ($modSupport);
|| defined( $modules{ $dev_hash->{TYPE} }{$TYPE}{map} ) );
RemoveInternalTimer("$name|$dev"); RemoveInternalTimer("$name|$dev");
delete $dev_hash->{pM_update} delete $dev_hash->{pM_update}
@@ -1009,23 +979,42 @@ sub powerMap_unload($$) {
return powerMap_load( $n, $d, 1 ); return powerMap_load( $n, $d, 1 );
} }
sub powerMap_FindPowerMaps(;$) { sub powerMap_findPowerMaps(;$) {
my ($device) = @_; my ($device) = @_;
my %maps; my %maps;
# collect all active definitions # directly return any existing device specific definition
unless ($device) { if ( $device && $device !~ /^:/ ) {
foreach ( devspec2array("i:TYPE=.*:FILTER=powerMap=.+") ) { return {}
unless ( defined( $defs{$device} )
&& defined( $defs{$device}{TYPE} ) );
return $defs{$device}{powerMap}{map}
if ( $defs{$device}{powerMap}{map}
&& ref( $defs{$device}{powerMap}{map} ) eq "HASH"
&& keys %{ $defs{$device}{powerMap}{map} } );
}
# get all devices with direct powerMap definitions
else {
foreach ( devspec2array("i:powerMap=.+") ) {
$maps{$_}{map} = $defs{$_}{powerMap}{map} $maps{$_}{map} = $defs{$_}{powerMap}{map}
if ( $defs{$_}{powerMap}{map} if ( $defs{$_}{powerMap}{map}
&& ref( $defs{$_}{powerMap}{map} ) eq "HASH" && ref( $defs{$_}{powerMap}{map} ) eq "HASH"
&& keys %{ $defs{$_}{powerMap}{map} } ); && keys %{ $defs{$_}{powerMap}{map} } );
} }
if ( $device && $device eq ":PM_INITIALIZED" ) {
foreach ( devspec2array("a:powerMap=.+") ) {
$maps{$_}{map} = $_ if ( !$maps{$_}{map} );
}
}
} }
# add templates from modules # search templates from modules
foreach my $TYPE ( keys %modules ) { foreach my $TYPE ( $device
&& $device !~ /^:/ ? $defs{$device}{TYPE} : keys %modules )
{
next unless ( $modules{$TYPE}{powerMap} ); next unless ( $modules{$TYPE}{powerMap} );
my $t = $modules{$TYPE}{powerMap}; my $t = $modules{$TYPE}{powerMap};
my $modelSupport = 0; my $modelSupport = 0;
@@ -1075,9 +1064,8 @@ sub powerMap_FindPowerMaps(;$) {
} }
} }
unless ( $device && $device =~ /^MODULE:/ ) { # find possible template for each Fhem device
unless ($device) {
# find possible template for each Fhem device
foreach my $TYPE ( keys %powerMap_tmpl ) { foreach my $TYPE ( keys %powerMap_tmpl ) {
next unless ( $modules{$TYPE} ); next unless ( $modules{$TYPE} );
@@ -1130,8 +1118,10 @@ sub powerMap_FindPowerMaps(;$) {
} }
} }
} }
}
# filter devices where no reading exists # filter devices where no reading exists
unless ( $device && $device eq ":PM_INITIALIZED" ) {
foreach my $d ( keys %maps ) { foreach my $d ( keys %maps ) {
if ( !$maps{$d}{map} || ref( $maps{$d}{map} ) ne "HASH" ) { if ( !$maps{$d}{map} || ref( $maps{$d}{map} ) ne "HASH" ) {
delete $maps{$d}; delete $maps{$d};
@@ -1150,26 +1140,18 @@ sub powerMap_FindPowerMaps(;$) {
} }
} }
if ( $device && $device =~ /^MODULE:(.*)$/ ) { return {}
return if ( !$maps{$1} ); if ( $device && $device !~ /^:/ && !defined( $maps{$device} ) );
return \$maps{$1}; return \$maps{$device} if ( $device && $device !~ /^:/ );
}
return if ( $device && !$maps{$device} );
return \$maps{$device} if ($device);
return \%maps; return \%maps;
} }
sub powerMap_power($$$;$) { sub powerMap_power($$$;$) {
my ( $name, $dev, $event, $loop ) = @_; my ( $name, $dev, $event, $loop ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
my $power = 0; my $power = 0;
my $powerMap = my $powerMap = powerMap_findPowerMaps($dev);
$defs{$dev}{$TYPE}{map} ? $defs{$dev}{$TYPE}{map}
: (
$defs{$dev}{$TYPE}{map} ? $defs{$dev}{$TYPE}{map}
: $modules{ $defs{$dev}{TYPE} }{$TYPE}{map}
);
return unless ( defined($powerMap) and ref($powerMap) eq "HASH" ); return unless ( defined($powerMap) and ref($powerMap) eq "HASH" );
@@ -1535,7 +1517,7 @@ sub powerMap_update($;$) {
<br> <br>
In case several power values need to be summarized, the name of other readings may be added after In case several power values need to be summarized, the name of other readings may be added after
number value, separated by comma. The current status of that reading will then be considered for number value, separated by comma. The current status of that reading will then be considered for
the total power calculcation. To consider all readings known to powerMap, just as an *. the total power calculcation. To consider all readings known to powerMap, just as an *.<br>
<br> <br>
Example for FS20 socket: Example for FS20 socket:
<ul> <ul>
@@ -1705,7 +1687,7 @@ sub powerMap_update($;$) {
Readings direkt hinter dem eigentliche Wert mit einem Komma abgetrennt angegeben werden. Readings direkt hinter dem eigentliche Wert mit einem Komma abgetrennt angegeben werden.
Der aktuelle Status dieses Readings wird dann bei der Berechnung des Gesamtverbrauchs ebenfalls Der aktuelle Status dieses Readings wird dann bei der Berechnung des Gesamtverbrauchs ebenfalls
ber&uumL;cksichtigt. Sollen alle in powerMap bekannten Readings ber&uuml;cksichtigt werden, kann ber&uumL;cksichtigt. Sollen alle in powerMap bekannten Readings ber&uuml;cksichtigt werden, kann
auch einfach ein * angegeben werden. auch einfach ein * angegeben werden.<br>
<br> <br>
Beispiel f&uuml;r einen FS20 Stecker: Beispiel f&uuml;r einen FS20 Stecker:
<ul> <ul>