mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-09 14:47:00 +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.
|
||||
# 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
|
||||
- bugfix: lib/FHEM/Core/Authentication/Passwords.pm
|
||||
change commandref
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
# 89_AndroidDB
|
||||
#
|
||||
# Version 0.2
|
||||
# Version 0.3
|
||||
#
|
||||
# FHEM Integration for Android Devices
|
||||
#
|
||||
@ -195,6 +195,11 @@ sub Attr ($@)
|
||||
$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') {
|
||||
delete $PRESET{_custom_} if (exists($PRESET{_custom_}));
|
||||
@ -203,6 +208,49 @@ sub Attr ($@)
|
||||
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;
|
||||
|
||||
=pod
|
||||
@ -258,10 +306,21 @@ sub Attr ($@)
|
||||
Several macro definitions can be specified by seperating them using a blank character.
|
||||
</li><br/>
|
||||
<a name="preset"></a>
|
||||
<li><b>preset <Preset></b><br/>
|
||||
Select a preset of keycode macros. If the same macro name is defined in the selected
|
||||
<li><b>preset {<PresetName>|@<PresetFileName>}</b><br/>
|
||||
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
|
||||
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/>
|
||||
</ul>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
# 89_AndroidDBHost
|
||||
#
|
||||
# Version 0.2
|
||||
# Version 0.3
|
||||
#
|
||||
# FHEM Integration for Android Debug Bridge
|
||||
#
|
||||
@ -45,6 +45,7 @@ package AndroidDBHost;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Dumper;
|
||||
use IPC::Open3;
|
||||
|
||||
use SetExtensions;
|
||||
@ -59,6 +60,7 @@ BEGIN {
|
||||
readingsBulkUpdateIfChanged
|
||||
readingsBeginUpdate
|
||||
readingsEndUpdate
|
||||
devspec2array
|
||||
Log3
|
||||
AttrVal
|
||||
ReadingsVal
|
||||
@ -67,6 +69,7 @@ BEGIN {
|
||||
init_done
|
||||
deviceEvents
|
||||
gettimeofday
|
||||
defs
|
||||
))
|
||||
};
|
||||
|
||||
@ -172,10 +175,35 @@ sub CheckADBServer ($)
|
||||
}
|
||||
|
||||
readingsSingleUpdate ($hash, 'state', $newState, 1);
|
||||
|
||||
# Update status of client devices
|
||||
UpdateClientStates ($hash) if ($newState eq 'running');
|
||||
|
||||
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
|
||||
##############################################################################
|
||||
@ -199,7 +227,7 @@ sub Set ($@)
|
||||
my $opt = shift @$a // return 'No set command specified';
|
||||
|
||||
# Preprare list of available commands
|
||||
my $options = 'command start:noArg stop:noArg';
|
||||
my $options = 'command disconnectAll:noArg start:noArg stop:noArg';
|
||||
|
||||
$opt = lc($opt);
|
||||
|
||||
@ -225,6 +253,11 @@ sub Set ($@)
|
||||
my ($rc, $result, $error) = Execute ($hash, $command, '.*', @$a);
|
||||
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 {
|
||||
return "Unknown argument $opt, choose one of $options";
|
||||
}
|
||||
@ -242,7 +275,7 @@ sub Get ($@)
|
||||
my $opt = shift @$a // return 'No get command specified';
|
||||
|
||||
# Prepare list of available commands
|
||||
my $options = 'status:noArg';
|
||||
my $options = 'devices:noArg status:noArg';
|
||||
|
||||
$opt = lc($opt);
|
||||
|
||||
@ -251,6 +284,22 @@ sub Get ($@)
|
||||
readingsSingleUpdate ($hash, 'state', $status, 1);
|
||||
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 {
|
||||
return "Unknown argument $opt, choose one of $options";
|
||||
}
|
||||
@ -316,7 +365,7 @@ sub Execute ($@)
|
||||
# -1 = Error
|
||||
# 0 = No active connections
|
||||
# 1 = Current device connected
|
||||
# 2 = Multiple devices connected (need to disconnect)
|
||||
# 2 = Other / multiple device(s) connected (need to disconnect)
|
||||
##############################################################################
|
||||
|
||||
sub IsConnected ($)
|
||||
@ -326,14 +375,13 @@ sub IsConnected ($)
|
||||
my $ioHash = $clHash->{IODev} // return -1;
|
||||
|
||||
# Get active connections
|
||||
my ($rc, $result, $error) = Execute ($ioHash, 'devices', 'list');
|
||||
return -1 if ($rc == 0);
|
||||
my $device = GetDeviceList ($ioHash) // return -1;
|
||||
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 (scalar(@devices) == 1 && $devices[0] eq $clHash->{ADBDevice}) {
|
||||
return 1;
|
||||
if ($devCount == 1) {
|
||||
return exists($device->{$clHash->{ADBDevice}}) ? 1 : 2;
|
||||
}
|
||||
elsif (scalar(@devices) > 1) {
|
||||
elsif ($devCount > 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -395,6 +443,27 @@ sub Disconnect ($)
|
||||
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
|
||||
#
|
||||
@ -455,15 +524,18 @@ sub TCPConnect ($$$)
|
||||
Dependencies: Perl module IPC::Open3, Android Platform Tools
|
||||
<br/><br/>
|
||||
Android DB Platform Tools installation:<br/>
|
||||
Debian/Raspbian: apt-get install android-sdk-platform-tools<br/>
|
||||
Windows/MacOSX/Linux x86: <a href="https://developer.android.com/studio/releases/platform-tools">Android Developer Portal</a>
|
||||
<br/><br/>
|
||||
<ul>
|
||||
<li>Debian/Raspbian: apt-get install android-sdk-platform-tools</li>
|
||||
<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>
|
||||
<b>Define</b><br/><br/>
|
||||
<ul>
|
||||
<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'.
|
||||
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>
|
||||
<br/>
|
||||
</ul>
|
||||
|
Loading…
x
Reference in New Issue
Block a user