2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-28 08:54:51 +00:00

AndroidDB: Fixed bug in attribute createReadings

git-svn-id: https://svn.fhem.de/fhem/trunk@25897 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2022-03-30 12:13:03 +00:00
parent f91abc569f
commit e4e5dc7630
3 changed files with 335 additions and 303 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- bugfix: 89_AndroidDB: Fixed bug in attribute createReadings
- feature: 89_AndroidDB: Added creation of readings for shell commands - feature: 89_AndroidDB: Added creation of readings for shell commands
- feature: 98_archetype: new option for FILTER in actual_.* attributes - feature: 98_archetype: new option for FILTER in actual_.* attributes
- change: 98_archetype: now packaged, extend commandref - change: 98_archetype: now packaged, extend commandref

View File

@ -4,7 +4,7 @@
# #
# 89_AndroidDB # 89_AndroidDB
# #
# Version 0.8 # Version 0.9
# #
# FHEM Integration for Android Devices # FHEM Integration for Android Devices
# #
@ -25,8 +25,7 @@ use strict;
use warnings; use warnings;
use SetExtensions; use SetExtensions;
sub AndroidDB_Initialize ($) sub AndroidDB_Initialize ($) {
{
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "AndroidDB::Define"; $hash->{DefFn} = "AndroidDB::Define";
@ -37,7 +36,9 @@ sub AndroidDB_Initialize ($)
$hash->{ShutdownFn} = "AndroidDB::Shutdown"; $hash->{ShutdownFn} = "AndroidDB::Shutdown";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = 'connect:0,1 createReadings macros:textField-long preset presetFile '.$readingFnAttributes; $hash->{AttrList} =
'connect:0,1 createReadings macros:textField-long preset presetFile '
. $readingFnAttributes;
$data{RC_layout}{MagentaTVStick} = "AndroidDB::RCLayoutMagentaTVStick"; $data{RC_layout}{MagentaTVStick} = "AndroidDB::RCLayoutMagentaTVStick";
$data{RC_layout}{MagentaOne} = "AndroidDB::RCLayoutMagentaOne"; $data{RC_layout}{MagentaOne} = "AndroidDB::RCLayoutMagentaOne";
@ -52,8 +53,10 @@ use SetExtensions;
use Storable qw(dclone); use Storable qw(dclone);
use GPUtils qw(:all); use GPUtils qw(:all);
BEGIN { BEGIN {
GP_Import(qw( GP_Import(
qw(
readingsSingleUpdate readingsSingleUpdate
readingsBulkUpdate readingsBulkUpdate
readingsBulkUpdateIfChanged readingsBulkUpdateIfChanged
@ -77,8 +80,10 @@ BEGIN {
modules modules
data data
init_done init_done
)) )
}; );
}
# Remote control presets # Remote control presets
my $PRESET = { my $PRESET = {
@ -159,67 +164,65 @@ my $PRESET = {
} }
}; };
# Command presets # Command presets
my $MACRO = { }; my $MACRO = { };
sub Define ($$$) sub Define ($$$) {
{ my ( $hash, $a, $h ) = @_;
my ($hash, $a, $h) = @_;
my $usage = "define $hash->{NAME} AndroidDB {NameOrIP[:Port]}"; my $usage = "define $hash->{NAME} AndroidDB {NameOrIP[:Port]}";
return $usage if (scalar(@$a) < 3); return $usage if ( scalar(@$a) < 3 );
# Set parameters # Set parameters
my ($devName, $devPort) = split (':', $$a[2]); my ( $devName, $devPort ) = split( ':', $$a[2] );
$hash->{ADBDevice} = $devName.':'.($devPort // '5555'); $hash->{ADBDevice} = $devName . ':' . ( $devPort // '5555' );
AssignIoPort ($hash); AssignIoPort($hash);
$attr{$hash->{NAME}}{webCmd} = 'remoteControl'; $attr{ $hash->{NAME} }{webCmd} = 'remoteControl';
# Clone predefined presets and macros # Clone predefined presets and macros
$hash->{adb}{preset} = dclone $PRESET; $hash->{adb}{preset} = dclone $PRESET;
$hash->{adb}{macro} = dclone $MACRO; $hash->{adb}{macro} = dclone $MACRO;
InitAfterStart ($hash) if ($init_done); InitAfterStart($hash) if ($init_done);
return undef; return undef;
} }
sub InitAfterStart ($) sub InitAfterStart ($) {
{
my ($hash) = @_; my ($hash) = @_;
my @presets = map { $_ eq '_custom_' ? () : $_ } keys %{$hash->{adb}{preset}}; my @presets =
map { $_ eq '_custom_' ? () : $_ } keys %{ $hash->{adb}{preset} };
if (scalar(@presets) > 0) { if ( scalar(@presets) > 0 ) {
my $attrPreset = 'preset:select,'.join(',',@presets); my $attrPreset = 'preset:select,' . join( ',', @presets );
my $attributes = $modules{AndroidDB}{AttrList}; my $attributes = $modules{AndroidDB}{AttrList};
$attributes =~ s/preset/$attrPreset/; $attributes =~ s/preset/$attrPreset/;
setDevAttrList ($hash->{NAME}, $attributes); setDevAttrList( $hash->{NAME}, $attributes );
} }
} }
sub Undef ($$) sub Undef ($$) {
{ my ( $hash, $name ) = @_;
my ($hash, $name) = @_;
AndroidDBHost::Disconnect ($hash); AndroidDBHost::Disconnect($hash);
return undef; return undef;
} }
sub Shutdown ($)
{ sub Shutdown ($) {
my ($hash) = @_; my ($hash) = @_;
AndroidDBHost::Disconnect ($hash); AndroidDBHost::Disconnect($hash);
} }
sub Set ($@) sub Set ($@) {
{ my ( $hash, $a, $h ) = @_;
my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a // return 'No set command specified'; my $opt = shift @$a // return 'No set command specified';
@ -229,115 +232,138 @@ sub Set ($@)
# #
# Standard commands # Standard commands
my $options = 'exportPresets reboot rollHorz rollVert sendKey sendNumKeys sendText shell tap'; my $options =
'exportPresets reboot rollHorz rollVert sendKey sendNumKeys sendText shell tap';
# Add remote control key presets to command remoteControl # Add remote control key presets to command remoteControl
my @presetList = (); my @presetList = ();
my $preset = AttrVal ($name, 'preset', ''); my $preset = AttrVal( $name, 'preset', '' );
push @presetList, sort keys %{$hash->{adb}{preset}{$preset}} if ($preset ne '' && exists($hash->{adb}{preset}{$preset})); push @presetList, sort keys %{ $hash->{adb}{preset}{$preset} }
push @presetList, sort keys %{$hash->{adb}{preset}{_custom_}} if (exists($hash->{adb}{preset}{_custom_})); if ( $preset ne '' && exists( $hash->{adb}{preset}{$preset} ) );
push @presetList, sort keys %{ $hash->{adb}{preset}{_custom_} }
if ( exists( $hash->{adb}{preset}{_custom_} ) );
my %e1; my %e1;
$options .= ' remoteControl:'.join(',', sort grep { !$e1{$_}++ } @presetList) if (scalar(@presetList) > 0); $options .=
' remoteControl:' . join( ',', sort grep { !$e1{$_}++ } @presetList )
if ( scalar(@presetList) > 0 );
# Add remote control layouts to command createRemote # Add remote control layouts to command createRemote
my @layouts = keys %{$data{RC_layout}}; my @layouts = keys %{ $data{RC_layout} };
$options .= ' createRemote:'.join(',', sort @layouts) if (scalar(@layouts) > 0); $options .= ' createRemote:' . join( ',', sort @layouts )
if ( scalar(@layouts) > 0 );
# Add command macros to command list # Add command macros to command list
my @macroList = (); my @macroList = ();
push @macroList, sort keys %{$hash->{adb}{macro}{$preset}} if ($preset ne '' && exists($hash->{adb}{macro}{$preset})); push @macroList, sort keys %{ $hash->{adb}{macro}{$preset} }
push @macroList, sort keys %{$hash->{adb}{macro}{_custom_}} if (exists($hash->{adb}{macro}{_custom_})); if ( $preset ne '' && exists( $hash->{adb}{macro}{$preset} ) );
push @macroList, sort keys %{ $hash->{adb}{macro}{_custom_} }
if ( exists( $hash->{adb}{macro}{_custom_} ) );
my %e2; my %e2;
$options .= ' '.join(' ', sort grep { !$e2{$_}++ } @macroList) if (scalar(@macroList) > 0); $options .= ' ' . join( ' ', sort grep { !$e2{$_}++ } @macroList )
if ( scalar(@macroList) > 0 );
my $lcopt = lc($opt); my $lcopt = lc($opt);
if ($lcopt eq 'sendkey') { if ( $lcopt eq 'sendkey' ) {
return "Usage: set $name $opt [--longpress] KeyCode [...]" if (scalar(@$a) == 0); return "Usage: set $name $opt [--longpress] KeyCode [...]"
if ( scalar(@$a) == 0 );
return "Only one KeyCode allowed when option '--longpress' is specified" return "Only one KeyCode allowed when option '--longpress' is specified"
if ($$a[0] eq '--longpress' && scalar(@$a) > 2); if ( $$a[0] eq '--longpress' && scalar(@$a) > 2 );
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'keyevent', @$a); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'keyevent', @$a );
return $error if ($rc == 0); return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'sendnumkeys') { elsif ( $lcopt eq 'sendnumkeys' ) {
my $number = shift @$a // return "Usage: set $name $opt Number"; my $number = shift @$a // return "Usage: set $name $opt Number";
return 'Parameter Number must be in range 1-9999' if ($number !~ /^[0-9]+$/ || $number < 1 || $number > 9999); return 'Parameter Number must be in range 1-9999'
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'text', $number); if ( $number !~ /^[0-9]+$/ || $number < 1 || $number > 9999 );
return $error if ($rc == 0); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'text', $number );
return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'sendtext') { elsif ( $lcopt eq 'sendtext' ) {
return "Usage: set $name $opt Text" if (scalar(@$a) < 1); return "Usage: set $name $opt Text" if ( scalar(@$a) < 1 );
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'text', join(' ',@$a)); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'text', join( ' ', @$a ) );
return $error if ($rc == 0); return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'reboot') { elsif ( $lcopt eq 'reboot' ) {
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, $opt); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, $opt );
return $error if ($rc == 0); return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'shell') { elsif ( $lcopt eq 'shell' ) {
return "Usage: set $name $opt ShellCommand" if (scalar(@$a) == 0); return "Usage: set $name $opt ShellCommand" if ( scalar(@$a) == 0 );
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, $opt, '.*', @$a); my $shellCommand = @$a[0];
return $error if ($rc == 0); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, $opt, '.*', @$a );
my $createReadings = AttrVal ($name, 'createReadings', ''); return $error if ( $rc == 0 );
return $result if ($createReadings eq '' || $createReadings !~ /$createReadings/); my $createReadings = AttrVal( $name, 'createReadings', '' );
UpdateReadings ($hash, $result); return $result
if ( $createReadings eq '' || $shellCommand !~ /$createReadings/ );
UpdateReadings( $hash, $result );
} }
elsif ($lcopt eq 'remotecontrol') { elsif ( $lcopt eq 'remotecontrol' ) {
my $macroName = shift @$a // return "Usage: set $name $opt MacroName"; my $macroName = shift @$a // return "Usage: set $name $opt MacroName";
$preset = '_custom_' if (exists($hash->{adb}{preset}{_custom_}) && exists($hash->{adb}{preset}{_custom_}{$macroName})); $preset = '_custom_'
if (exists( $hash->{adb}{preset}{_custom_} )
&& exists( $hash->{adb}{preset}{_custom_}{$macroName} ) );
return "Preset and/or macro $macroName not defined in preset $preset" return "Preset and/or macro $macroName not defined in preset $preset"
if ($preset eq '' || !exists($hash->{adb}{preset}{$preset}{$macroName})); if ( $preset eq ''
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'keyevent', || !exists( $hash->{adb}{preset}{$preset}{$macroName} ) );
split (',', $hash->{adb}{preset}{$preset}{$macroName})); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'keyevent',
return $error if ($rc == 0); split( ',', $hash->{adb}{preset}{$preset}{$macroName} ) );
return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'tap') { elsif ( $lcopt eq 'tap' ) {
my ($x, $y) = @$a; my ( $x, $y ) = @$a;
return "Usage: set $name $opt tap X Y" if (!defined($y)); return "Usage: set $name $opt tap X Y" if ( !defined($y) );
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'tap', $x, $y); my ( $rc, $result, $error ) =
return $error if ($rc == 0); AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'tap', $x, $y );
return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'rollhorz' || $lcopt eq 'rollvert') { elsif ( $lcopt eq 'rollhorz' || $lcopt eq 'rollvert' ) {
my $delta = shift @$a // return "Usage: set $name $opt Delta"; my $delta = shift @$a // return "Usage: set $name $opt Delta";
my ($dx, $dy) = $opt eq 'rollhorz' ? ($delta, 0) : (0, $delta); my ( $dx, $dy ) = $opt eq 'rollhorz' ? ( $delta, 0 ) : ( 0, $delta );
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, 'shell', '.*', 'input', 'roll', $dx, $dy); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, 'shell', '.*', 'input', 'roll', $dx, $dy );
return $error if ($rc == 0); return $error if ( $rc == 0 );
} }
elsif ($lcopt eq 'createremote') { elsif ( $lcopt eq 'createremote' ) {
my $layout = shift @$a // return "Usage: set $name $opt LayoutName"; my $layout = shift @$a // return "Usage: set $name $opt LayoutName";
my $rcName = $name.'_RC'; my $rcName = $name . '_RC';
return "$name: Can't create remotecontrol device $rcName" return "$name: Can't create remotecontrol device $rcName"
if (CommandDefine (undef, "$rcName remotecontrol")); if ( CommandDefine( undef, "$rcName remotecontrol" ) );
Log3 $name, 2, "$name: Created remotecontrol device $rcName"; Log3 $name, 2, "$name: Created remotecontrol device $rcName";
return "$name: Can't select layout $layout for remotecontrol device $rcName" return
if (CommandSet (undef, "$rcName layout $layout")); "$name: Can't select layout $layout for remotecontrol device $rcName"
if ( CommandSet( undef, "$rcName layout $layout" ) );
Log3 $name, 2, "Selected layout $layout for $rcName"; Log3 $name, 2, "Selected layout $layout for $rcName";
my $room = AttrVal ($name, 'room', ''); my $room = AttrVal( $name, 'room', '' );
if ($room ne '') { if ( $room ne '' ) {
Log3 $name, 2, "$name: Assigning $rcName to room $room"; Log3 $name, 2, "$name: Assigning $rcName to room $room";
CommandAttr (undef, "$rcName room $room"); CommandAttr( undef, "$rcName room $room" );
} }
CommandSet (undef, "$rcName makenotify $name"); CommandSet( undef, "$rcName makenotify $name" );
CommandAttr (undef, "$name group $name"); CommandAttr( undef, "$name group $name" );
CommandAttr (undef, "$rcName group $name"); CommandAttr( undef, "$rcName group $name" );
Log3 $name, 2, "Created notify device notify_$rcName"; Log3 $name, 2, "Created notify device notify_$rcName";
} }
elsif ($lcopt eq 'exportpresets') { elsif ( $lcopt eq 'exportpresets' ) {
my $filename = shift @$a // return "Usage: set $name $opt Filename"; my $filename = shift @$a // return "Usage: set $name $opt Filename";
my $rc = ExportPresets ($hash, $filename); my $rc = ExportPresets( $hash, $filename );
return "Error while saving presets to file $filename" if ($rc == 0); return "Error while saving presets to file $filename" if ( $rc == 0 );
return "Presets saved to file $filename"; return "Presets saved to file $filename";
} }
elsif (exists($hash->{adb}{macro}{_custom_}) && exists($hash->{adb}{macro}{_custom_}{$opt})) { elsif ( exists( $hash->{adb}{macro}{_custom_} )
my ($args, $pars) = parseParams ($hash->{adb}{macro}{_custom_}{$opt}); && exists( $hash->{adb}{macro}{_custom_}{$opt} ) )
{
my ( $args, $pars ) = parseParams( $hash->{adb}{macro}{_custom_}{$opt} );
my $cmd = shift @$args; my $cmd = shift @$args;
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, $cmd, '.*', @$args); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, $cmd, '.*', @$args );
return $rc == 0 ? $error : $result; return $rc == 0 ? $error : $result;
} }
elsif ($preset ne '' && exists($hash->{adb}{macro}{$preset}) && exists($hash->{adb}{macro}{$preset}{$opt})) { elsif ( $preset ne ''
my ($args, $pars) = parseParams ($hash->{adb}{macro}{$preset}{$opt}); && exists( $hash->{adb}{macro}{$preset} )
&& exists( $hash->{adb}{macro}{$preset}{$opt} ) )
{
my ( $args, $pars ) = parseParams( $hash->{adb}{macro}{$preset}{$opt} );
my $cmd = shift @$args; my $cmd = shift @$args;
my ($rc, $result, $error) = AndroidDBHost::Run ($hash, $cmd, '.*', @$args); my ( $rc, $result, $error ) = AndroidDBHost::Run( $hash, $cmd, '.*', @$args );
return $rc == 0 ? $error : $result; return $rc == 0 ? $error : $result;
} }
else { else {
@ -345,6 +371,7 @@ sub Set ($@)
} }
} }
sub Get ($@) sub Get ($@)
{ {
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
@ -427,6 +454,7 @@ sub Attr ($@)
return undef; return undef;
} }
############################################################################## ##############################################################################
# Load macro definitions from file # Load macro definitions from file
# File format: # File format:

View File

@ -37,6 +37,7 @@ sub AndroidDBHost_Initialize ($)
$hash->{ShutdownFn} = "AndroidDBHost::Shutdown"; $hash->{ShutdownFn} = "AndroidDBHost::Shutdown";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = $readingFnAttributes;
} }
package AndroidDBHost; package AndroidDBHost;
@ -53,7 +54,8 @@ use IPC::Open3;
use GPUtils qw(:all); use GPUtils qw(:all);
BEGIN { BEGIN {
GP_Import(qw( GP_Import(
qw(
readingsSingleUpdate readingsSingleUpdate
readingsBulkUpdate readingsBulkUpdate
readingsBulkUpdateIfChanged readingsBulkUpdateIfChanged
@ -69,7 +71,8 @@ BEGIN {
deviceEvents deviceEvents
gettimeofday gettimeofday
defs defs
)) )
)
}; };
sub Define ($$$) sub Define ($$$)