diff --git a/fhem/FHEM/32_SYSSTAT.pm b/fhem/FHEM/32_SYSSTAT.pm
index 00ad50026..92dbb3269 100644
--- a/fhem/FHEM/32_SYSSTAT.pm
+++ b/fhem/FHEM/32_SYSSTAT.pm
@@ -782,6 +782,22 @@ SYSSTAT_Attr($$$)
SYSSTAT_Connect($hash)
+ } elsif( $attrName eq 'noSSH') {
+ if( $cmd eq 'set' && $attrVal ne '0' ) {
+ $attr{$name}{$attrName} = $attrVal;
+ if( $hash->{HOST} ) {
+ SYSSTAT_Disconnect($hash);
+ delete $hash->{CONNECTS};
+ delete $hash->{helper}{has_proc_loadavg};
+ delete $hash->{helper}{has_proc_stat};
+ delete $hash->{helper}{has_proc_uptime};
+ }
+
+ } else {
+ SYSSTAT_Connect($hash);
+
+ }
+
} elsif( $attrName eq 'filesystems') {
my @filesystems = split(',',$attrVal);
@{$hash->{filesystems}} = @filesystems;
@@ -1000,7 +1016,7 @@ SYSSTAT_GetUpdateSNMP($)
}
if(!$hash->{LOCAL}) {
- return if( IsDisabled($name) > 0 );
+ return undef if( IsDisabled($name) > 0 );
}
SYSSTAT_getLoadAVGSNMP($hash);
@@ -1054,7 +1070,7 @@ SYSSTAT_BlockingCall($)
my ($hash) = @_;
my $name = $hash->{NAME};
- $hash->{BlockingResult} = ();
+ $hash->{BlockingResult} = {};
SYSSTAT_GetUpdateSNMP($hash);
diff --git a/fhem/FHEM/39_siri.pm b/fhem/FHEM/39_siri.pm
index eb865b3c7..c5c76ec54 100644
--- a/fhem/FHEM/39_siri.pm
+++ b/fhem/FHEM/39_siri.pm
@@ -6,10 +6,16 @@ package main;
use strict;
use warnings;
+use CoProcess;
+
+use HttpUtils;
+
use vars qw(%modules);
use vars qw(%defs);
use vars qw(%attr);
use vars qw($readingFnAttributes);
+use vars qw($FW_ME);
+
sub Log($$);
sub Log3($$$);
@@ -18,16 +24,44 @@ siri_Initialize($)
{
my ($hash) = @_;
- #$hash->{ReadFn} = "siri_Read";
+ $hash->{ReadFn} = "siri_Read";
$hash->{DefFn} = "siri_Define";
- #$hash->{NOTIFYDEV} = "global";
- #$hash->{NotifyFn} = "siri_Notify";
+ $hash->{NotifyFn} = "siri_Notify";
$hash->{UndefFn} = "siri_Undefine";
- #$hash->{SetFn} = "siri_Set";
+ $hash->{DelayedShutdownFn} = "siri_DelayedShutdownFn";
+ $hash->{ShutdownFn} = "siri_Shutdown";
+ $hash->{SetFn} = "siri_Set";
#$hash->{GetFn} = "siri_Get";
- #$hash->{AttrFn} = "siri_Attr";
- $hash->{AttrList} = "$readingFnAttributes";
+ $hash->{AttrFn} = "siri_Attr";
+ $hash->{AttrList} = "homebridgeFHEM-cmd ".
+ #"homebridgeFHEM-config ".
+ #"homebridgeFHEM-home ".
+ "homebridgeFHEM-log ".
+ "homebridgeFHEM-params ".
+ #"homebridgeFHEM-auth ".
+ #"homebridgeFHEM-filter ".
+ "homebridgeFHEM-host homebridgeFHEM-sshUser ".
+ "nrarchive ".
+ "disable:1 disabledForIntervals ".
+ $readingFnAttributes;
+
+ $hash->{FW_detailFn} = "siri_detailFn";
+ $hash->{FW_deviceOverview} = 1;
+
+ if( 0 ) {
+ my $m = 'homebridge-fhem';
+ my ($defptr, $ldata);
+ if($modules{$m}) {
+ $defptr = $modules{$m}{defptr};
+ $ldata = $modules{$m}{ldata};
+ }
+ $modules{$m} = $hash;
+ $modules{$m}{ORDER} = 39;
+ $modules{$m}{LOADED} = 1;
+ $modules{$m}{defptr} = $defptr if($defptr);
+ $modules{$m}{ldata} = $ldata if($ldata);
+ }
}
#####################################
@@ -45,13 +79,39 @@ siri_Define($$)
$hash->{NAME} = $name;
my $d = $modules{$hash->{TYPE}}{defptr};
+ #return "$hash->{TYPE} device already defined as $d->{NAME}. please use homebridge-fhem for other instances." if( defined($d) && $hash->{TYPE} eq 'siri' );
return "$hash->{TYPE} device already defined as $d->{NAME}." if( defined($d) );
$modules{$hash->{TYPE}}{defptr} = $hash;
addToAttrList("$hash->{TYPE}Name");
-
$hash->{STATE} = 'active';
+ $hash->{NOTIFYDEV} = "global,global:npmjs.*homebridge.*";
+
+ if( $attr{global}{logdir} ) {
+ CommandAttr(undef, "$name homebridgeFHEM-log %L/homebridgeFHEM-%Y-%m-%d.log") if( !AttrVal($name, 'homebridgeFHEM-log', undef ) );
+ } else {
+ CommandAttr(undef, "$name homebridgeFHEM-log ./log/homebridgeFHEM-%Y-%m-%d.log") if( !AttrVal($name, 'homebridgeFHEM-log', undef ) );
+ }
+
+ #CommandAttr(undef, "$name homebridgeFHEM-filter homebridgeFHEM=..*") if( !AttrVal($name, 'homebridgeFHEM-filter', undef ) );
+
+ if( !AttrVal($name, 'devStateIcon', undef ) ) {
+ CommandAttr(undef, "$name stateFormat homebridge");
+ CommandAttr(undef, "$name devStateIcon stopped:control_home\@red:start stopping:control_on_off\@orange running.*:control_on_off\@green:stop")
+ }
+
+
+ $hash->{CoProcess} = { name => 'homebridge',
+ cmdFn => 'siri_getCMD',
+ };
+
+ if( $init_done ) {
+ CoProcess::start($hash);
+ } else {
+ $hash->{STATE} = 'active';
+ }
+
return undef;
}
@@ -61,7 +121,19 @@ siri_Notify($$)
my ($hash,$dev) = @_;
return if($dev->{NAME} ne "global");
- return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}));
+
+ if( grep(m/^npmjs:BEGIN.*homebridge.*/, @{$dev->{CHANGED}}) ) {
+ CoProcess::stop($hash);
+ return undef;
+
+ } elsif( grep(m/^npmjs:FINISH.*homebridge.*/, @{$dev->{CHANGED}}) ) {
+ CoProcess::start($hash);
+ return undef;
+
+ } elsif( grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}) ) {
+ CoProcess::start($hash);
+ return undef;
+ }
return undef;
}
@@ -70,11 +142,229 @@ sub
siri_Undefine($$)
{
my ($hash, $arg) = @_;
+ my $name = $hash->{NAME};
+
+ if( $hash->{PID} ) {
+ $hash->{undefine} = 1;
+ $hash->{undefine} = $hash->{CL} if( $hash->{CL} );
+
+ $hash->{reason} = 'delete';
+ CoProcess::stop($hash);
+
+ return "$name will be deleted after homebridge has stopped or after 5 seconds. whatever comes first.";
+ }
delete $modules{$hash->{TYPE}}{defptr};
return undef;
}
+sub
+siri_DelayedShutdownFn($)
+{
+ my ($hash) = @_;
+
+ if( $hash->{PID} ) {
+ $hash->{shutdown} = 1;
+ $hash->{shutdown} = $hash->{CL} if( $hash->{CL} );
+
+ $hash->{reason} = 'shutdown';
+ CoProcess::stop($hash);
+
+ return 1;
+ }
+
+ return undef;
+}
+
+sub
+siri_Shutdown($)
+{
+ my ($hash) = @_;
+
+ CoProcess::terminate($hash);
+
+ delete $modules{$hash->{TYPE}}{defptr};
+
+ return undef;
+}
+
+sub
+siri_detailFn($$$$)
+{
+ my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
+ my $hash = $defs{$d};
+ my $name = $hash->{NAME};
+
+ my $ret;
+
+ my $logfile = AttrVal($name, 'homebridgeFHEM-log', 'FHEM' );
+ if( $logfile && $logfile ne 'FHEM' ) {
+ my $name = 'homebridgeFHEMlog';
+ $ret .= "". AttrVal($name, "alias", "Logfile") ."
";
+ }
+
+ if( $hash->{PID} ) {
+ if( $hash->{helper}{Code} ) {
+ $hash->{helper}{Code} =~ s/[^0-9\-]//g;
+ $ret .= "
" if( $ret );
+ $ret .= "Code: $hash->{helper}{Code}
";
+ }
+
+ if( $hash->{helper}{'Setup Payload'} ) {
+ $ret .= "
" if( $ret );
+ $ret .= "Setup: {helper}{'Setup Payload'}\">$hash->{helper}{'Setup Payload'}
";
+ }
+
+ if( $hash->{helper}{'Setup Payload'} ) {
+ $ret .= "
" if( $ret );
+ $ret .= "
{helper}{'Setup Payload'});
+ $ret .= "\"/>
";
+
+ #https://developers.google.com/chart/infographics/docs/qr_codes
+ #https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=Hello%20world&choe=UTF-8
+ #http://chart.apis.google.com/chart?chs=200x200&cht=qr&chld=L&chl=
+ #http://goqr.me/api/doc/create-qr-code/
+ #https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Example
+ }
+ }
+
+
+ return $ret;
+}
+
+sub
+siri_Read($)
+{
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ my $buf = CoProcess::readFn($hash);
+ return undef if( !$buf );
+
+ my $data = $hash->{helper}{PARTIAL};
+ $data .= $buf;
+
+ while($data =~ m/\n/) {
+ ($buf,$data) = split("\n", $data, 2);
+
+ #Log3 $name, 5, "$name: read: $buf";
+
+
+ if( $buf =~ m/^\*\*\* ([^\s]+) (.+)/ ) {
+ my $service = $1;
+ my $message = $2;
+
+ if( $service eq 'FHEM:' ) {
+ if( $message =~ m/^connection failed(: (.*))?/ ) {
+ my $reason = $2;
+
+ $hash->{reason} = 'failed to connect to fhem';
+ $hash->{reason} .= ": $reason" if( $reason );
+ CoProcess::stop($hash);
+ }
+ }
+
+ } elsif( $buf =~ /^\[/ ) {
+ delete $hash->{helper}{next};
+
+ } elsif( 1 && $buf =~ '^X-HM://' ) {
+ $hash->{helper}{'Setup Payload'} = $buf;
+
+ } elsif( 0 && $buf =~ /^Setup Payload:$/ ) {
+ $hash->{helper}{next} = 'Setup Payload';
+ delete $hash->{helper}{$hash->{helper}{next}};
+
+ } elsif( 0 && $buf =~ /^Scan this code/ ) {
+ $hash->{helper}{next} = 'QR-Code';
+ delete $hash->{helper}{$hash->{helper}{next}};
+
+ } elsif( $buf =~ /enter this code with your HomeKit app/ ) {
+ $hash->{helper}{next} = 'Code';
+ delete $hash->{helper}{$hash->{helper}{next}};
+
+ } elsif( $hash->{helper}{next} ) {
+ $hash->{helper}{$hash->{helper}{next}} .= "\n" if( $hash->{$hash->{helper}{next}} );
+ $hash->{helper}{$hash->{helper}{next}} .= $buf;
+
+ }
+ }
+
+ $hash->{PARTIAL} = $data;
+
+ return undef;
+}
+
+sub
+siri_getCMD($)
+{
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ return undef if( !$init_done );
+
+ if( 0 && !AttrVal($name, 'homebridgeFHEM-config', undef ) ) {
+ siri_configDefault($hash);
+ }
+
+ delete $hash->{helper}{Code};
+ delete $hash->{helper}{'QR-Code'};
+ delete $hash->{helper}{'Setup Paload'};
+
+ return undef if( IsDisabled($name) );
+ #return undef if( ReadingsVal($name, 'homebridge', 'unknown') =~ m/^running/ );
+
+
+ my $ssh_cmd;
+ if( my $host = AttrVal($name, 'homebridgeFHEM-host', undef ) ) {
+ my $ssh = qx( which ssh ); chomp( $ssh );
+ if( my $user = AttrVal($name, 'homebridgeFHEM-sshUser', undef ) ) {
+ $ssh_cmd = "$ssh $user\@$host";
+ } else {
+ $ssh_cmd = "$ssh $host";
+ }
+
+ Log3 $name, 3, "$name: using ssh cmd $ssh_cmd";
+ }
+
+ my $cmd;
+ if( $ssh_cmd ) {
+ $cmd = AttrVal( $name, "homebridgeFHEM-cmd", qx( $ssh_cmd which homebridge ) );
+ } else {
+ $cmd = AttrVal( $name, "homebridgeFHEM-cmd", qx( which homebridge ) );
+ }
+ chomp( $cmd );
+
+ if( !$ssh_cmd && !(-X $cmd) ) {
+ my $msg = "homebridge not installed. install with 'sudo npm install -g homebridge homebridge-fhem'.";
+ $msg = "$cmd does not exist" if( $cmd );
+ return (undef, $msg);
+ }
+
+ $cmd = "$ssh_cmd $cmd" if( $ssh_cmd );
+
+ if( my $home = AttrVal($name, 'homebridgeFHEM-home', undef ) ) {
+ $home = $ENV{'PWD'} if( $home eq 'PWD' );
+ $ENV{'HOME'} = $home;
+ Log3 $name, 2, "$name: setting \$HOME to $home";
+ }
+ if( my $config = AttrVal($name, 'homebridgeFHEM-config', undef ) ) {
+ if( $ssh_cmd ) {
+ qx( $ssh_cmd "cat > /tmp/homebridge.cfg" < $config );
+ $cmd .= " -c /tmp/homebridge.cfg";
+ } else {
+ $cmd .= " -c $config";
+ }
+ }
+ if( my $params = AttrVal($name, 'homebridgeFHEM-params', undef ) ) {
+ $cmd .= " $params";
+ }
+
+ Log3 $name, 2, "$name: starting homebridge $cmd";
+
+ return $cmd;
+
+}
sub
siri_Set($$@)
@@ -83,6 +373,8 @@ siri_Set($$@)
my $list = "";
+ return CoProcess::setCommands($hash, $list, $cmd, @args);
+
return "Unknown argument $cmd, choose one of $list";
}
@@ -96,30 +388,6 @@ siri_Get($$@)
return "Unknown argument $cmd, choose one of $list";
}
-sub
-siri_Parse($$;$)
-{
- my ($hash,$data,$peerhost) = @_;
- my $name = $hash->{NAME};
-}
-
-sub
-siri_Read($)
-{
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- my $len;
- my $buf;
-
- $len = $hash->{CD}->recv($buf, 1024);
- if( !defined($len) || !$len ) {
-Log 1, "!!!!!!!!!!";
- return;
- }
-
- siri_Parse($hash, $buf, $hash->{CD}->peerhost);
-}
sub
siri_Attr($$$)
@@ -129,9 +397,40 @@ siri_Attr($$$)
my $orig = $attrVal;
my $hash = $defs{$name};
- if( $attrName eq "disable" ) {
+ if( $attrName eq 'homebridgeFHEM-log' ) {
+ if( $cmd eq "set" && $attrVal && $attrVal ne 'FHEM' ) {
+ fhem( "defmod -temporary homebridgeFHEMlog FileLog $attrVal fakelog" );
+ CommandAttr( undef, 'homebridgeFHEMlog room hidden' );
+ #if( my $room = AttrVal($name, "room", undef ) ) {
+ # CommandAttr( undef,"homebridgeFHEMlog room $room" );
+ #}
+ $hash->{logfile} = $attrVal;
+ } else {
+ fhem( "delete homebridgeFHEMlog" );
+ }
+
+ $attr{$name}{$attrName} = $attrVal;
+
+ CoProcess::start($hash);
+ } elsif( $attrName eq 'homebridgeFHEM-params' ) {
+ $attr{$name}{$attrName} = $attrVal;
+
+ CoProcess::start($hash);
+
+ } elsif( $attrName eq 'homebridgeFHEM-host' ) {
+ $attr{$name}{$attrName} = $attrVal;
+
+ CoProcess::start($hash);
+
+ } elsif( $attrName eq 'homebridgeFHEM-sshUser' ) {
+ $attr{$name}{$attrName} = $attrVal;
+
+ CoProcess::start($hash);
+
}
+
+
if( $cmd eq 'set' ) {
if( $orig ne $attrVal ) {
$attr{$name}{$attrName} = $attrVal;
diff --git a/fhem/FHEM/CoProcess.pm b/fhem/FHEM/CoProcess.pm
index 890d1c905..a0fbd1b36 100644
--- a/fhem/FHEM/CoProcess.pm
+++ b/fhem/FHEM/CoProcess.pm
@@ -26,6 +26,11 @@ package CoProcess;
use POSIX;
use Socket;
+use constant { NotFound => 1,
+ NotExecutable => 2,
+ };
+
+
sub
Info($$@) {
my @ret;
@@ -40,7 +45,7 @@ Info($$@) {
push @ret, $line;
}
-
+
unshift @ret, sprintf( "\n%-15s %-15s %-35s %-19s %-19s %8s %s", 'DEVICE', 'NAME', 'state', 'LAST START', 'LAST STOP', 'PID', 'logfile' ) if( @ret );
push @ret, "No CoProcesses are currently used" if(!@ret);
@@ -146,7 +151,34 @@ start($;$) {
stop($hash);
return undef;
}
+
delete $hash->{restart};
+ my( $exec, $params) = split( ' ', $cmd, 2 );
+
+ if( $exec !~ m'/' ) {
+ $exec = qx( which $exec ); chomp( $exec );
+ }
+
+ if( !(-X $exec) ) {
+ if( $exec ) {
+ my $error = "$exec: not executable";
+ $hash->{CoProcess}{state} = "stopped; $error";
+ main::readingsSingleUpdate($hash, $hash->{CoProcess}{name}, $hash->{CoProcess}{state}, 1 ) if( $hash->{CoProcess}{name} );
+ main::Log3 $name, 2, "$name: $error";
+ return NotExecutable;
+ }
+
+ my $error = "not found";
+ $hash->{CoProcess}{state} = "stopped; $error";
+ main::readingsSingleUpdate($hash, $hash->{CoProcess}{name}, $hash->{CoProcess}{state}, 1 ) if( $hash->{CoProcess}{name} );
+ main::Log3 $name, 2, "$name: $error";
+ return NotFound;
+ } else {
+ main::Log3 $name, 5, "$name: using $exec";
+ }
+
+ $cmd = "$exec $params";
+
my ($child, $parent);
# SOCK_NONBLOCK ?