mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-10 03:06:37 +00:00
AndroidDB: Improved connection handling
git-svn-id: https://svn.fhem.de/fhem/trunk@24481 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
ad2e58d90c
commit
9ada644ab0
@ -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: Connection handling improved
|
||||||
- feature: 73_AutoShuttersControl: add abort rain unprotection waiting time
|
- feature: 73_AutoShuttersControl: add abort rain unprotection waiting time
|
||||||
- bugfix: lib/FHEM/Core/Authentication/Passwords.pm
|
- bugfix: lib/FHEM/Core/Authentication/Passwords.pm
|
||||||
change commandref
|
change commandref
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# 89_AndroidDB
|
# 89_AndroidDB
|
||||||
#
|
#
|
||||||
# Version 0.2
|
# Version 0.3
|
||||||
#
|
#
|
||||||
# FHEM Integration for Android Devices
|
# FHEM Integration for Android Devices
|
||||||
#
|
#
|
||||||
@ -195,6 +195,11 @@ sub Attr ($@)
|
|||||||
$PRESET{_custom_}{$macroName} = $macroKeycodes;
|
$PRESET{_custom_}{$macroName} = $macroKeycodes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elsif ($attrName eq 'preset' && $attrVal =~ /^\@(.+)$/) {
|
||||||
|
if (!LoadPreset ($hash, $1)) {
|
||||||
|
Log3 $hash, 2, "Can't load preset from file $1";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elsif ($cmd eq 'del') {
|
elsif ($cmd eq 'del') {
|
||||||
delete $PRESET{_custom_} if (exists($PRESET{_custom_}));
|
delete $PRESET{_custom_} if (exists($PRESET{_custom_}));
|
||||||
@ -203,6 +208,49 @@ sub Attr ($@)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Load macro definitions from file
|
||||||
|
# File format:
|
||||||
|
# - Lines starting with a # are treated as comments
|
||||||
|
# - Lines containing a single word are setting the preset name for the
|
||||||
|
# following lines
|
||||||
|
# - Lines in format Name:KeyList are defining a macro. KeyList is a comma
|
||||||
|
# separated list of keycodes.
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub LoadPreset ($$)
|
||||||
|
{
|
||||||
|
my ($hash, $fileName) = @_;
|
||||||
|
|
||||||
|
my @lines;
|
||||||
|
if (open (PRESETFILE, "<$fileName")) {
|
||||||
|
@lines = <PRESETFILE>;
|
||||||
|
close (PRESETFILE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
chomp @lines;
|
||||||
|
my $presetName = '';
|
||||||
|
|
||||||
|
foreach my $l (@lines) {
|
||||||
|
next if ($l =~ /^#/); # Comments are allowed
|
||||||
|
my ($macroName, $keyList) = split (':', $l);
|
||||||
|
if (!defined($keyList)) {
|
||||||
|
$presetName = $macroName;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
elsif (defined($keyList) && $presetName eq '') {
|
||||||
|
Log3 $hash, 2, "Preset name must be specified before first macro definition in file $fileName";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$PRESET{$presetName}{$macroName} = $keyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
@ -258,10 +306,21 @@ sub Attr ($@)
|
|||||||
Several macro definitions can be specified by seperating them using a blank character.
|
Several macro definitions can be specified by seperating them using a blank character.
|
||||||
</li><br/>
|
</li><br/>
|
||||||
<a name="preset"></a>
|
<a name="preset"></a>
|
||||||
<li><b>preset <Preset></b><br/>
|
<li><b>preset {<PresetName>|@<PresetFileName>}</b><br/>
|
||||||
Select a preset of keycode macros. If the same macro name is defined in the selected
|
Select a preset of keycode macros or load a set of macros from a preset defintion
|
||||||
|
file. If the same macro name is defined in the selected
|
||||||
preset and in attribute 'macros', the definition in the 'macros' attribute overwrites
|
preset and in attribute 'macros', the definition in the 'macros' attribute overwrites
|
||||||
the definition in the preset.
|
the definition in the preset.<br/>
|
||||||
|
A preset defintion file is using the following format:<br/>
|
||||||
|
<pre>
|
||||||
|
# Comment
|
||||||
|
PresetName1
|
||||||
|
MacroName1:KeyCode[,...]
|
||||||
|
MacroName2:KeyCode[,...]
|
||||||
|
...
|
||||||
|
PresetName2
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
</li><br/>
|
</li><br/>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# 89_AndroidDBHost
|
# 89_AndroidDBHost
|
||||||
#
|
#
|
||||||
# Version 0.2
|
# Version 0.3
|
||||||
#
|
#
|
||||||
# FHEM Integration for Android Debug Bridge
|
# FHEM Integration for Android Debug Bridge
|
||||||
#
|
#
|
||||||
@ -45,6 +45,7 @@ package AndroidDBHost;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
use IPC::Open3;
|
use IPC::Open3;
|
||||||
|
|
||||||
use SetExtensions;
|
use SetExtensions;
|
||||||
@ -59,6 +60,7 @@ BEGIN {
|
|||||||
readingsBulkUpdateIfChanged
|
readingsBulkUpdateIfChanged
|
||||||
readingsBeginUpdate
|
readingsBeginUpdate
|
||||||
readingsEndUpdate
|
readingsEndUpdate
|
||||||
|
devspec2array
|
||||||
Log3
|
Log3
|
||||||
AttrVal
|
AttrVal
|
||||||
ReadingsVal
|
ReadingsVal
|
||||||
@ -67,6 +69,7 @@ BEGIN {
|
|||||||
init_done
|
init_done
|
||||||
deviceEvents
|
deviceEvents
|
||||||
gettimeofday
|
gettimeofday
|
||||||
|
defs
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,9 +176,34 @@ sub CheckADBServer ($)
|
|||||||
|
|
||||||
readingsSingleUpdate ($hash, 'state', $newState, 1);
|
readingsSingleUpdate ($hash, 'state', $newState, 1);
|
||||||
|
|
||||||
|
# Update status of client devices
|
||||||
|
UpdateClientStates ($hash) if ($newState eq 'running');
|
||||||
|
|
||||||
return $newState eq 'running' ? 1 : 0;
|
return $newState eq 'running' ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Update connection states of client devices
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub UpdateClientStates ($)
|
||||||
|
{
|
||||||
|
my $hash = shift;
|
||||||
|
|
||||||
|
my $device = GetDeviceList ($hash) // return 0;
|
||||||
|
|
||||||
|
foreach my $d (keys %defs) {
|
||||||
|
my $clHash = $defs{$d};
|
||||||
|
if ($clHash->{TYPE} eq 'AndroidDB') {
|
||||||
|
my $clState = $device->{$clHash->{ADBDevice}} // 'disconnected';
|
||||||
|
$clState =~ s/device/connected/;
|
||||||
|
readingsSingleUpdate ($clHash, 'state', $clState, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Check if ADB server is running by connecting to port
|
# Check if ADB server is running by connecting to port
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -199,7 +227,7 @@ sub Set ($@)
|
|||||||
my $opt = shift @$a // return 'No set command specified';
|
my $opt = shift @$a // return 'No set command specified';
|
||||||
|
|
||||||
# Preprare list of available commands
|
# Preprare list of available commands
|
||||||
my $options = 'command start:noArg stop:noArg';
|
my $options = 'command disconnectAll:noArg start:noArg stop:noArg';
|
||||||
|
|
||||||
$opt = lc($opt);
|
$opt = lc($opt);
|
||||||
|
|
||||||
@ -225,6 +253,11 @@ sub Set ($@)
|
|||||||
my ($rc, $result, $error) = Execute ($hash, $command, '.*', @$a);
|
my ($rc, $result, $error) = Execute ($hash, $command, '.*', @$a);
|
||||||
return $result.$error;
|
return $result.$error;
|
||||||
}
|
}
|
||||||
|
elsif ($opt eq 'disconnect') {
|
||||||
|
my ($rc, $result, $error) = Execute ($Hash, 'disconnect', 'disconnected');
|
||||||
|
UpdateClientStates ($hash);
|
||||||
|
return "Disconnecting all devices failed $result $error" if ($rc == 0);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return "Unknown argument $opt, choose one of $options";
|
return "Unknown argument $opt, choose one of $options";
|
||||||
}
|
}
|
||||||
@ -242,7 +275,7 @@ sub Get ($@)
|
|||||||
my $opt = shift @$a // return 'No get command specified';
|
my $opt = shift @$a // return 'No get command specified';
|
||||||
|
|
||||||
# Prepare list of available commands
|
# Prepare list of available commands
|
||||||
my $options = 'status:noArg';
|
my $options = 'devices:noArg status:noArg';
|
||||||
|
|
||||||
$opt = lc($opt);
|
$opt = lc($opt);
|
||||||
|
|
||||||
@ -251,6 +284,22 @@ sub Get ($@)
|
|||||||
readingsSingleUpdate ($hash, 'state', $status, 1);
|
readingsSingleUpdate ($hash, 'state', $status, 1);
|
||||||
return "ADB server $status";
|
return "ADB server $status";
|
||||||
}
|
}
|
||||||
|
elsif ($opt eq 'devices') {
|
||||||
|
my $device = GetDeviceList ($hash) // return 'Cannot read device list';
|
||||||
|
my @clDevices = devspec2array ('TYPE=AndroidDB');
|
||||||
|
my $list = '<html>List of devices:<br/><br/>';
|
||||||
|
foreach my $d (keys %$device) {
|
||||||
|
my @f = ();
|
||||||
|
foreach my $cd (@clDevices) {
|
||||||
|
if (exists($defs{$cd}) && $defs{$cd}{ADBDevice} eq $d) {
|
||||||
|
push @f, $cd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$list .= sprintf ('%22s %20s %s<br/>', $d, join(',', @f), $device->{$d});
|
||||||
|
}
|
||||||
|
$list .= '</html>';
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return "Unknown argument $opt, choose one of $options";
|
return "Unknown argument $opt, choose one of $options";
|
||||||
}
|
}
|
||||||
@ -316,7 +365,7 @@ sub Execute ($@)
|
|||||||
# -1 = Error
|
# -1 = Error
|
||||||
# 0 = No active connections
|
# 0 = No active connections
|
||||||
# 1 = Current device connected
|
# 1 = Current device connected
|
||||||
# 2 = Multiple devices connected (need to disconnect)
|
# 2 = Other / multiple device(s) connected (need to disconnect)
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
sub IsConnected ($)
|
sub IsConnected ($)
|
||||||
@ -326,14 +375,13 @@ sub IsConnected ($)
|
|||||||
my $ioHash = $clHash->{IODev} // return -1;
|
my $ioHash = $clHash->{IODev} // return -1;
|
||||||
|
|
||||||
# Get active connections
|
# Get active connections
|
||||||
my ($rc, $result, $error) = Execute ($ioHash, 'devices', 'list');
|
my $device = GetDeviceList ($ioHash) // return -1;
|
||||||
return -1 if ($rc == 0);
|
my $devCount = keys %$device;
|
||||||
|
|
||||||
my @devices = $result =~ /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]+)/g;
|
if ($devCount == 1) {
|
||||||
if (scalar(@devices) == 1 && $devices[0] eq $clHash->{ADBDevice}) {
|
return exists($device->{$clHash->{ADBDevice}}) ? 1 : 2;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
elsif (scalar(@devices) > 1) {
|
elsif ($devCount > 1) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,6 +443,27 @@ sub Disconnect ($)
|
|||||||
return $rc;
|
return $rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Get list of devices
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub GetDeviceList ($)
|
||||||
|
{
|
||||||
|
my $hash = shift;
|
||||||
|
|
||||||
|
my ($rc, $result, $error) = Execute ($hash, 'devices');
|
||||||
|
return undef if ($rc == 0);
|
||||||
|
|
||||||
|
my %devState = ();
|
||||||
|
my @devices = $result =~ /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]+\s+[a-zA-Z0-9]+)/g;
|
||||||
|
foreach my $d (@devices) {
|
||||||
|
my ($address, $state) = split /\s+/, $d;
|
||||||
|
$devState{$address} = $state // 'disconnected';
|
||||||
|
}
|
||||||
|
|
||||||
|
return \%devState;
|
||||||
|
}
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Execute commmand and return status code and command output
|
# Execute commmand and return status code and command output
|
||||||
#
|
#
|
||||||
@ -455,15 +524,18 @@ sub TCPConnect ($$$)
|
|||||||
Dependencies: Perl module IPC::Open3, Android Platform Tools
|
Dependencies: Perl module IPC::Open3, Android Platform Tools
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
Android DB Platform Tools installation:<br/>
|
Android DB Platform Tools installation:<br/>
|
||||||
Debian/Raspbian: apt-get install android-sdk-platform-tools<br/>
|
<ul>
|
||||||
Windows/MacOSX/Linux x86: <a href="https://developer.android.com/studio/releases/platform-tools">Android Developer Portal</a>
|
<li>Debian/Raspbian: apt-get install android-sdk-platform-tools</li>
|
||||||
<br/><br/>
|
<li>Windows/MacOSX/Linux x86: <a href="https://developer.android.com/studio/releases/platform-tools">Android Developer Portal</a></li>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
<a name="AndroidDBHostdefine"></a>
|
<a name="AndroidDBHostdefine"></a>
|
||||||
<b>Define</b><br/><br/>
|
<b>Define</b><br/><br/>
|
||||||
<ul>
|
<ul>
|
||||||
<code>define <name> AndroidDBHost [server=<host>}[:<port>]] [adb=<path>]</code><br/><br/>
|
<code>define <name> AndroidDBHost [server=<host>}[:<port>]] [adb=<path>]</code><br/><br/>
|
||||||
The parameter 'host' is the hostname of the system, where the ADB server is running. Default is 'localhost'.
|
The parameter 'host' is the hostname of the system, where the ADB server is running. Default is 'localhost'.
|
||||||
Parameter 'adb' can be used to specify the path to the adb command (must include 'adb' or 'adb.exe').
|
Parameter 'adb' can be used to specify the path to the adb command (must include 'adb' or 'adb.exe').<br/>
|
||||||
|
<b>Note:</b> The adb command must be executable by the account under which FHEM is running.
|
||||||
</ul>
|
</ul>
|
||||||
<br/>
|
<br/>
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user