mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
1c6cd4c1b9
git-svn-id: https://svn.fhem.de/fhem/trunk@27227 2b470e98-0d58-463d-a4d8-8e2adae1ed80
800 lines
25 KiB
Perl
800 lines
25 KiB
Perl
#####################################################################################
|
|
# $Id$
|
|
#
|
|
# Usage
|
|
#
|
|
# define <name> serviced <service name> [user@ip-address]
|
|
#
|
|
#####################################################################################
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Blocking;
|
|
use Time::HiRes;
|
|
use vars qw{%defs};
|
|
|
|
my $servicedVersion = "1.2.9";
|
|
|
|
sub serviced_shutdownwait($);
|
|
|
|
sub serviced_Initialize($)
|
|
{
|
|
my ($hash) = @_;
|
|
$hash->{AttrFn} = "serviced_Attr";
|
|
$hash->{DefFn} = "serviced_Define";
|
|
$hash->{GetFn} = "serviced_Get";
|
|
$hash->{NotifyFn} = "serviced_Notify";
|
|
$hash->{SetFn} = "serviced_Set";
|
|
$hash->{ShutdownFn} = "serviced_Shutdown";
|
|
$hash->{UndefFn} = "serviced_Undef";
|
|
$hash->{AttrList} = "disable:1,0 ".
|
|
"disabledForIntervals ".
|
|
"serviceAutostart ".
|
|
"serviceAutostop ".
|
|
"serviceGetStatusOnInit:0,1 ".
|
|
"serviceInitd:1,0 ".
|
|
"serviceLogin ".
|
|
"servicePort ".
|
|
"serviceRegexFailed ".
|
|
"serviceRegexStarted ".
|
|
"serviceRegexStarting ".
|
|
"serviceRegexStopped ".
|
|
"serviceStatusInterval ".
|
|
"serviceStatusLine:1,2,3,4,5,6,7,8,9,last ".
|
|
"serviceSudo:0,1 ".
|
|
$readingFnAttributes;
|
|
}
|
|
|
|
sub serviced_Define($$)
|
|
{
|
|
my ($hash,$def) = @_;
|
|
my @args = split " ",$def;
|
|
return "Usage: define <name> serviced <service name> [user\@ip-address] [port]"
|
|
if (@args < 3 || @args > 5);
|
|
my ($name,$type,$service,$remote,$port) = @args;
|
|
return "Remote host must be like 'pi\@192.168.2.22' or 'pi\@myserver' or 'pi\@192.168.2.22 222' if you need to declare a SSH port other than the default port!"
|
|
if (($remote && $remote !~ /^\w{2,}@(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[\w\.\-_]{2,})$/) || ($port && $port !~ /^\d{2,5}$/));
|
|
RemoveInternalTimer($hash);
|
|
$hash->{NOTIFYDEV} = "global";
|
|
$hash->{SERVICENAME} = $service;
|
|
$hash->{VERSION} = $servicedVersion;
|
|
if ($init_done && !defined $hash->{OLDDEF})
|
|
{
|
|
$attr{$name}{alias} = "Service $service";
|
|
$attr{$name}{cmdIcon} = "restart:rc_REPEAT stop:rc_STOP status:rc_INFO start:rc_PLAY";
|
|
$attr{$name}{devStateIcon} = "Initialized|status:light_question error|failed:light_exclamation running:audio_play:stop stopped:audio_stop:start stopping:audio_stop .*starting:audio_repeat";
|
|
$attr{$name}{room} = "Services";
|
|
$attr{$name}{icon} = "hue_room_garage";
|
|
$attr{$name}{serviceLogin} = $remote if ($remote);
|
|
$attr{$name}{servicePort} = $port if ($port);
|
|
$attr{$name}{webCmd} = "start:restart:stop:status";
|
|
if (grep /^homebridgeMapping/,split(" ",AttrVal("global","userattr","")))
|
|
{
|
|
$attr{$name}{genericDeviceType} = "switch";
|
|
$attr{$name}{homebridgeMapping} = "On=state,valueOff=/stopped|failed/,cmdOff=stop,cmdOn=start\n".
|
|
"StatusJammed=state,values=/error|failed/:JAMMED;/.*/:NOT_JAMMED";
|
|
}
|
|
readingsSingleUpdate($hash,"state","Initialized",1);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub serviced_Undef($$)
|
|
{
|
|
my ($hash,$name) = @_;
|
|
RemoveInternalTimer($hash);
|
|
BlockingKill($hash->{helper}{RUNNING_PID}) if ($hash->{helper}{RUNNING_PID});
|
|
return undef;
|
|
}
|
|
|
|
sub serviced_Notify($$)
|
|
{
|
|
my ($hash,$dev) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $devname = $dev->{NAME};
|
|
return if (IsDisabled($name));
|
|
my $events = deviceEvents($dev,0);
|
|
return if (!$events);
|
|
if ($devname eq "global" && grep /^INITIALIZED$/,@{$events})
|
|
{
|
|
if (AttrNum($name,"serviceGetStatusOnInit",1) || AttrNum($name,"serviceStatusInterval",0))
|
|
{
|
|
Log3 $name,4,"$name: get status of service \"$hash->{SERVICENAME}\" due to startup and/or interval";
|
|
serviced_GetUpdate($hash);
|
|
}
|
|
my $delay = AttrVal($name,"serviceAutostart",0);
|
|
$delay = $delay > 300 ? 300 : $delay;
|
|
if ($delay)
|
|
{
|
|
Log3 $name,3,"$name: starting service \"$hash->{SERVICENAME}\" with delay of $delay seconds";
|
|
InternalTimer(gettimeofday() + $delay,"serviced_Set","$name|start");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
sub serviced_Get($@)
|
|
{
|
|
my ($hash,$name,$cmd) = @_;
|
|
return if (IsDisabled($name) && $cmd ne "?");
|
|
my $params = "status:noArg";
|
|
if ($cmd eq "status")
|
|
{
|
|
return "Work already/still in progress... Please wait for the current process to finish."
|
|
if ($hash->{helper}{RUNNING_PID} && !$hash->{helper}{RUNNING_PID}{terminated});
|
|
serviced_Set($hash,$name,"status");
|
|
}
|
|
else
|
|
{
|
|
return "Unknown argument $cmd for $name, choose one of $params";
|
|
}
|
|
}
|
|
|
|
sub serviced_Set($@)
|
|
{
|
|
my ($hash,$name,$cmd) = @_;
|
|
if (ref $hash ne "HASH")
|
|
{
|
|
($name,$cmd) = split /\|/,$hash;
|
|
$hash = $defs{$name};
|
|
}
|
|
return if (IsDisabled($name) && $cmd ne "?");
|
|
my $params = "start:noArg stop:noArg restart:noArg status:noArg";
|
|
return "$cmd is not a valid command for $name, please choose one of $params"
|
|
if (!$cmd || $cmd eq "?" || !grep(/^$cmd:noArg$/,split " ",$params));
|
|
return "Work already/still in progress... Please wait for the current process to finish."
|
|
if ($hash->{helper}{RUNNING_PID} && !$hash->{helper}{RUNNING_PID}{terminated});
|
|
$cmd = "restart"
|
|
if ($cmd eq "start" && ReadingsVal($name,"state","") =~ /^running|starting|failed$/);
|
|
my $service = $hash->{SERVICENAME};
|
|
my $login = AttrVal($name,"serviceLogin","");
|
|
$login .= $login ? " -p ".AttrNum($name,"servicePort",22) : "";
|
|
my $sudo = AttrNum($name,"serviceSudo",1) && $login !~ /^root@/ ? "sudo " : "";
|
|
my $line = AttrVal($name,"serviceStatusLine",3);
|
|
my $com;
|
|
$com .= "ssh $login '" if ($login);
|
|
$com .= $sudo;
|
|
if (AttrNum($name,"serviceInitd",0))
|
|
{
|
|
$com .= "service $service $cmd";
|
|
}
|
|
else
|
|
{
|
|
$com .= "systemctl $cmd $service";
|
|
}
|
|
$com .= "'" if ($login);
|
|
Log3 $name,5,"$name: serviced_Set executing shell command: $com";
|
|
$com = encode_base64($com,"");
|
|
if ($hash->{LOCKFILE})
|
|
{
|
|
$hash->{helper}{RUNNING_PID} = BlockingCall("serviced_ExecCmd","$name|$cmd|$com|$line","serviced_ExecFinished");
|
|
}
|
|
else
|
|
{
|
|
$hash->{helper}{RUNNING_PID} = BlockingCall("serviced_ExecCmd","$name|$cmd|$com|$line","serviced_ExecFinished",301,"serviced_ExecAborted",$hash);
|
|
}
|
|
my $state = $cmd eq "status" ? $cmd : $cmd =~ /start/ ? $cmd."ing" : $cmd."ping";
|
|
readingsSingleUpdate($hash,"state",$state,1);
|
|
return;
|
|
}
|
|
|
|
sub serviced_Attr(@)
|
|
{
|
|
my ($cmd,$name,$attr_name,$attr_value) = @_;
|
|
my $hash = $defs{$name};
|
|
if ($cmd eq "set")
|
|
{
|
|
if ($attr_name =~ /^disable|serviceGetStatusOnInit|serviceInitd|serviceSudo$/)
|
|
{
|
|
return "$attr_value not valid, can only be 0 or 1!"
|
|
if ($attr_value !~ /^1|0$/);
|
|
if ($attr_name eq "disable")
|
|
{
|
|
BlockingKill($hash->{helper}{RUNNING_PID}) if ($hash->{helper}{RUNNING_PID});
|
|
}
|
|
}
|
|
elsif ($attr_name =~ /^serviceAutostart|serviceAutostop$/)
|
|
{
|
|
my $er = "$attr_value not valid for $attr_name, must be a number in seconds like 5 to automatically (re)start service after init of fhem (min: 1, max: 300)!";
|
|
$er = "$attr_value not valid for $attr_name, must be a timeout in seconds like 1 to automatically stop service while shutdown of fhem (min: 1, max: 300)!" if ($attr_name eq "serviceAutostop");
|
|
return $er
|
|
if ($attr_value !~ /^(\d{1,3})$/ || $1 > 300 || $1 < 1);
|
|
return;
|
|
}
|
|
elsif ($attr_name eq "serviceLogin")
|
|
{
|
|
return "$attr_value not valid for $attr_name, must be a ssh login string like 'pi\@192.168.2.22' or 'pi\@myserver'!"
|
|
if ($attr_value !~ /^\w{2,}@(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[\w\.\-_]{2,})$/);
|
|
}
|
|
elsif ($attr_name eq "servicePort")
|
|
{
|
|
return "$attr_value not valid for $attr_name, must be a port number like 22 or 222!"
|
|
if ($attr_value !~ /^\d{2,5}$/);
|
|
}
|
|
elsif ($attr_name =~ /^serviceRegexFailed|serviceRegexStopped|serviceRegexStarted|serviceRegexStarting$/)
|
|
{
|
|
my $ex = "dead|failed|exited";
|
|
$ex = "inactive|stopped" if ($attr_name eq "serviceRegexStopped");
|
|
$ex = "running|active" if ($attr_name eq "serviceRegexStarted");
|
|
$ex = "activating|starting" if ($attr_name eq "serviceRegexStarting");
|
|
return "$attr_value not valid for $attr_name, must be a regex like '$ex'!"
|
|
if ($attr_value !~ /^[\w\-_]{3,}(\|[\w\-_]{3,}){0,}$/);
|
|
}
|
|
elsif ($attr_name eq "serviceStatusInterval")
|
|
{
|
|
return "$attr_value not valid for $attr_name, must be a number in seconds like 300 (min: 5, max: 999999)!"
|
|
if ($attr_value !~ /^(\d{1,6})$/ || $1 < 5);
|
|
$hash->{helper}{interval} = $attr_value;
|
|
}
|
|
elsif ($attr_name eq "serviceStatusLine")
|
|
{
|
|
return "$attr_value not valid for $attr_name, must be a number like 2, for 2nd line of status output, or 'last' for last line of status output!"
|
|
if ($attr_value !~ /^(\d{1,2}|last)$/);
|
|
}
|
|
serviced_GetUpdate($hash);
|
|
}
|
|
else
|
|
{
|
|
if ($attr_name eq "disable")
|
|
{
|
|
serviced_GetUpdate($hash);
|
|
}
|
|
elsif ($attr_name eq "serviceStatusInterval")
|
|
{
|
|
$hash->{helper}{interval} = 0;
|
|
serviced_GetUpdate($hash);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
sub serviced_ExecCmd($)
|
|
{
|
|
my ($string) = @_;
|
|
my @a = split /\|/,$string;
|
|
my $name = $a[0];
|
|
my $cmd = $a[1];
|
|
my $com = decode_base64($a[2]);
|
|
my $line = $a[3];
|
|
my $hash = $defs{$name};
|
|
my $lockfile = $hash->{LOCKFILE};
|
|
my $er = 0;
|
|
$com .= " 2>&1" if ($cmd ne "status");
|
|
my @qx = qx($com);
|
|
if (!@qx && $cmd eq "status")
|
|
{
|
|
$com .= " 2>&1";
|
|
@qx = qx($com);
|
|
$er = 1;
|
|
}
|
|
Log3 $name,5,"$name: serviced_ExecCmd com: $com, line: $line";
|
|
my @ret;
|
|
my $re = "";
|
|
for (@qx)
|
|
{
|
|
chomp;
|
|
$_ =~ s/[\s\t ]{1,}/ /g;
|
|
$_ =~ s/(^ {1,}| {1,}$)//g;
|
|
push @ret,$_ if ($_);
|
|
}
|
|
$er = 1 if (@ret && $cmd ne "status");
|
|
if (!$er && @ret)
|
|
{
|
|
$re = $ret[@ret-1] if ($line eq "last" && $ret[@ret-1]);
|
|
$re = $ret[$line-1] if ($line =~ /^\d/ && $ret[$line-1]);
|
|
}
|
|
elsif (@ret)
|
|
{
|
|
$re = join " ",@ret;
|
|
}
|
|
if ($lockfile)
|
|
{
|
|
Log3 $name,3,"$name: shutdown sequence of service $name finished";
|
|
my $er = FileDelete($lockfile);
|
|
if ($er)
|
|
{
|
|
Log3 $name,2,"$name: error while deleting controlfile \"$lockfile\": $er";
|
|
}
|
|
else
|
|
{
|
|
Log3 $name,4,"$name: controlfile \"$lockfile\" deleted successfully";
|
|
}
|
|
}
|
|
$re = encode_base64($re,"");
|
|
return "$name|$er|$re";
|
|
}
|
|
|
|
sub serviced_ExecFinished($)
|
|
{
|
|
my ($string) = @_;
|
|
my @a = split /\|/,$string;
|
|
my $name = $a[0];
|
|
my $er = $a[1];
|
|
my $ret = decode_base64($a[2]) if ($a[2]);
|
|
my $hash = $defs{$name};
|
|
my $service = $hash->{SERVICENAME};
|
|
delete $hash->{helper}{RUNNING_PID};
|
|
if ($er)
|
|
{
|
|
readingsBeginUpdate($hash);
|
|
readingsBulkUpdate($hash,"state","error");
|
|
readingsBulkUpdate($hash,"error",$ret);
|
|
readingsEndUpdate($hash,1);
|
|
Log3 $name,3,"$name: Error: $ret";
|
|
}
|
|
elsif ($ret)
|
|
{
|
|
my $refail = AttrVal($name,"serviceRegexFailed","dead|failed|exited");
|
|
my $restop = AttrVal($name,"serviceRegexStopped","inactive|stopped");
|
|
my $restart = AttrVal($name,"serviceRegexStarted","running|active");
|
|
my $restarting = AttrVal($name,"serviceRegexStarting","activating|starting");
|
|
readingsBeginUpdate($hash);
|
|
readingsBulkUpdate($hash,"error","none");
|
|
readingsBulkUpdate($hash,"status",$ret);
|
|
if ($ret =~ /$restarting/)
|
|
{
|
|
readingsBulkUpdate($hash,"state","starting");
|
|
Log3 $name,4,"$name: Service \"$hash->{SERVICENAME}\" is starting";
|
|
}
|
|
elsif ($ret =~ /$restop/)
|
|
{
|
|
readingsBulkUpdate($hash,"state","stopped");
|
|
Log3 $name,4,"$name: Service \"$hash->{SERVICENAME}\" is stopped";
|
|
}
|
|
elsif ($ret =~ /$refail/)
|
|
{
|
|
readingsBulkUpdate($hash,"state","failed");
|
|
Log3 $name,4,"$name: Service \"$hash->{SERVICENAME}\" is failed";
|
|
}
|
|
elsif ($ret =~ /$restart/)
|
|
{
|
|
readingsBulkUpdate($hash,"state","running");
|
|
Log3 $name,4,"$name: Service \"$hash->{SERVICENAME}\" is started";
|
|
}
|
|
readingsEndUpdate($hash,1);
|
|
}
|
|
else
|
|
{
|
|
if (AttrNum($name,"serviceStatusInterval",0))
|
|
{
|
|
serviced_GetUpdate($hash);
|
|
}
|
|
else
|
|
{
|
|
serviced_Set($hash,$name,"status");
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub serviced_ExecAborted($)
|
|
{
|
|
my ($hash,$cause) = @_;
|
|
$cause = "BlockingCall was aborted due to 301 seconds timeout" if (!$cause);
|
|
my $name = $hash->{NAME};
|
|
delete $hash->{helper}{RUNNING_PID};
|
|
Log3 $name,2,"$name: BlockingCall aborted: $cause";
|
|
readingsBeginUpdate($hash);
|
|
readingsBulkUpdate($hash,"state","error");
|
|
readingsBulkUpdate($hash,"error",$cause);
|
|
readingsEndUpdate($hash,1);
|
|
return undef;
|
|
}
|
|
|
|
sub serviced_GetUpdate(@)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
RemoveInternalTimer($hash);
|
|
return if (IsDisabled($name) || !$init_done);
|
|
my $sec = defined $hash->{helper}{interval} ? $hash->{helper}{interval} : AttrNum($name,"serviceStatusInterval",undef);
|
|
delete $hash->{helper}{interval} if (defined $hash->{helper}{interval});
|
|
serviced_Set($hash,$name,"status");
|
|
return if (!$sec);
|
|
InternalTimer(gettimeofday() + $sec,"serviced_GetUpdate",$hash);
|
|
return;
|
|
}
|
|
|
|
sub serviced_Shutdown($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
return if (IsDisabled($name));
|
|
my $autostop = AttrNum($name,"serviceAutostop",0);
|
|
$autostop = $autostop > 300 ? 300 : $autostop;
|
|
if ($autostop)
|
|
{
|
|
$hash->{SHUTDOWNTIME} = time;
|
|
Log3 $name,3,"$name: stopping service \"$hash->{SERVICENAME}\" due to shutdown";
|
|
my $lockfile = AttrVal("global","modpath",".")."/log/".$name."_shut.lock";
|
|
my $er = FileWrite($lockfile,"controlfile shutdown sequence");
|
|
if ($er)
|
|
{
|
|
Log3 $name,2,"$name: error while creating controlfile \"$lockfile\": $er";
|
|
}
|
|
else
|
|
{
|
|
Log3 $name,4,"$name: controlfile \"$lockfile\" created successfully for shutdown-sequence \"$hash->{SERVICENAME}\" ";
|
|
$hash->{LOCKFILE} = $lockfile;
|
|
serviced_Set($hash,$name,"stop");
|
|
serviced_shutdownwait($hash);
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub serviced_shutdownwait($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $autostop = AttrVal($name,"serviceAutostop",0);
|
|
$autostop = $autostop > 300 ? 300 : $autostop;
|
|
my $lockfile = $hash->{LOCKFILE};
|
|
my ($er,undef) = FileRead($lockfile);
|
|
if (!$er)
|
|
{
|
|
sleep 1;
|
|
if (time > $hash->{SHUTDOWNTIME} + $autostop)
|
|
{
|
|
$er = FileDelete($lockfile);
|
|
if ($er)
|
|
{
|
|
Log3 $name,2,"$name: Error while deleting controlfile \"$lockfile\": $er";
|
|
Log3 $name,3,"$name: Maximum shutdown waittime of $autostop seconds excceeded, force shutdown.";
|
|
}
|
|
else
|
|
{
|
|
Log3 $name,3,"$name: Maximum shutdown waittime of $autostop seconds excceeded. Controlfile \"$lockfile\" deleted and force sutdown.";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return serviced_shutdownwait($hash);
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item device
|
|
=item summary local/remote services management
|
|
=item summary_DE lokale/entfernte Dienste Verwaltung
|
|
=begin html
|
|
|
|
<a id="serviced"></a>
|
|
<h3>serviced</h3>
|
|
<ul>
|
|
With <i>serviced</i> you are able to control running services either running on localhost or a remote host.<br>
|
|
The usual command are available: start/restart/stop/status.<br>
|
|
<br>
|
|
<a id="serviced-define"></a>
|
|
<p><b>Define</b></p>
|
|
<ul>
|
|
<code>define <name> serviced <service name> [<user@ip-address>]</code><br>
|
|
</ul>
|
|
<br>
|
|
Example for running serviced for local service(s):
|
|
<br><br>
|
|
<ul>
|
|
<code>define hb serviced homebridge</code><br>
|
|
</ul>
|
|
<br>
|
|
Example for running serviced for remote service(s):
|
|
<br><br>
|
|
<ul>
|
|
<code>define hyp serviced hyperion pi@192.168.1.4</code><br>
|
|
</ul>
|
|
<br>
|
|
For remote services you have to grant passwordless ssh access for the user which is running FHEM (usually fhem). You'll find a tutorial how to do that by visiting <a target="_blank" href="http://www.linuxproblem.org/art_9.html">this link</a>.
|
|
<br><br>
|
|
To use systemctl (systemd) or service (initd) you have to grant permissions to the system commands for the user which is running FHEM (usually fhem) by editing the sudoers file (/etc/sudoers) (visudo).
|
|
<br><br>
|
|
For systemd (please check your local paths):
|
|
<br>
|
|
<ul>
|
|
<code>fhem ALL=(ALL) NOPASSWD:/bin/systemctl</code>
|
|
</ul>
|
|
<br>
|
|
For initd (please check your local paths):
|
|
<br>
|
|
<ul>
|
|
<code>fhem ALL=(ALL) NOPASSWD:/usr/sbin/service</code>
|
|
</ul>
|
|
<br><br>
|
|
If you have homebridgeMapping in your attributes an appropriate mapping will be added, genericDeviceType as well.
|
|
<br>
|
|
<a id="serviced-set"></a>
|
|
<p><b>Set</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-set-start">start</a><br>
|
|
start the stopped service
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-stop">stop</a><br>
|
|
stop the started service
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-restart">restart</a><br>
|
|
restart the service
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-status">status</a><br>
|
|
get status of service
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-get"></a>
|
|
<p><b>Get</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-get-status">status</a><br>
|
|
get status of service<br>
|
|
same like 'set status'
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-attr"></a>
|
|
<p><b>Attributes</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-attr-serviceAutostart">serviceAutostart</a><br>
|
|
delay in seconds to automatically (re)start service after start of FHEM<br>
|
|
default:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceAutostop">serviceAutostop</a><br>
|
|
timeout in seconds to automatically stop service while shutdown of FHEM<br>
|
|
default:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceGetStatusOnInit">serviceGetStatusOnInit</a><br>
|
|
get status of service automatically on FHEM start<br>
|
|
default: 1
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceInitd">serviceInitd</a><br>
|
|
use initd (system) instead of systemd (systemctl)<br>
|
|
default: 0
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceLogin">serviceLogin</a><br>
|
|
ssh login string for services running on remote hosts<br>
|
|
passwordless ssh is mandatory<br>
|
|
default:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-servicePort">servicePort</a><br>
|
|
ssh port to use if other than default port (22)<br>
|
|
default: 22
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexFailed">serviceRegexFailed</a><br>
|
|
regex for failed status<br>
|
|
default: dead|failed|exited
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStarted">serviceRegexStarted</a><br>
|
|
regex for running status<br>
|
|
default: running|active
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStarting">serviceRegexStarting</a><br>
|
|
regex for starting status<br>
|
|
default: activating|starting
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStopped">serviceRegexStopped</a><br>
|
|
regex for stopped status<br>
|
|
default: inactive|stopped
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceStatusInterval">serviceStatusInterval</a><br>
|
|
interval of getting status automatically<br>
|
|
default:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceStatusLine">serviceStatusLine</a><br>
|
|
line number of status output containing the status information<br>
|
|
default: 3
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceSudo">serviceSudo</a><br>
|
|
use sudo<br>
|
|
default: 1
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-read"></a>
|
|
<p><b>Readings</b></p>
|
|
<p>All readings updates will create events.</p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-read-error">error</a><br>
|
|
last occured error, none if no error occured<br>
|
|
</li>
|
|
<li>
|
|
<a id="serviced-read-state">state</a><br>
|
|
current state
|
|
</li>
|
|
<li>
|
|
<a id="serviced-read-status">status</a><br>
|
|
last status line from 'get/set status'
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html
|
|
=begin html_DE
|
|
|
|
<a id="serviced"></a>
|
|
<h3>serviced</h3>
|
|
<ul>
|
|
Mit <i>serviced</i> können lokale und entfernte Dienste verwaltet werden.<br>
|
|
Die üblichen Kommandos sind verfügbar: start/restart/stop/status.<br>
|
|
<br>
|
|
<a id="serviced-define"></a>
|
|
<p><b>Define</b></p>
|
|
<ul>
|
|
<code>define <name> serviced <Dienst Name> [<user@ip-adresse>]</code><br>
|
|
</ul>
|
|
<br>
|
|
Beispiel serviced für lokale Dienste:
|
|
<br><br>
|
|
<ul>
|
|
<code>define hb serviced homebridge</code><br>
|
|
</ul>
|
|
<br>
|
|
Beispiel serviced für entfernte Dienste:
|
|
<br><br>
|
|
<ul>
|
|
<code>define hyp serviced hyperion pi@192.168.1.4</code><br>
|
|
</ul>
|
|
<br>
|
|
Für entfernte Dienste muss dem Benutzer unter dem FHEM läuft dass passwortlose Anmelden per SSH erlaubt werden. Eine Anleitung wie das zu machen geht ist unter <a target="_blank" href="http://www.linuxproblem.org/art_9.html">diesem Link</a> abrufbar.
|
|
<br><br>
|
|
Zur Benutzung von systemctl (systemd) oder service (initd) müssen dem Benutzer unter dem FHEM läuft die entsprechenden Rechte in der sudoers Datei erteilt werden (/etc/sudoers) (visudo).
|
|
<br><br>
|
|
Für systemd (bitte mit eigenen Pfaden abgleichen):
|
|
<br>
|
|
<ul>
|
|
<code>fhem ALL=(ALL) NOPASSWD:/bin/systemctl</code>
|
|
</ul>
|
|
<br>
|
|
Für initd (bitte mit eigenen Pfaden abgleichen):
|
|
<br>
|
|
<ul>
|
|
<code>fhem ALL=(ALL) NOPASSWD:/usr/sbin/service</code>
|
|
</ul>
|
|
<br><br>
|
|
Wenn homebridgeMapping in der Attributliste ist, so wird ein entsprechendes Mapping hinzugefügt, ebenso genericDeviceType.
|
|
<br>
|
|
<a id="serviced-set"></a>
|
|
<p><b>Set</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-set-start">start</a><br>
|
|
angehaltenen Dienst starten
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-stop">stop</a><br>
|
|
laufenden Dienst anhalten
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-restart">restart</a><br>
|
|
Dienst neu starten
|
|
</li>
|
|
<li>
|
|
<a id="serviced-set-status">status</a><br>
|
|
Status des Dienstes abrufen
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-get"></a>
|
|
<p><b>Get</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-get-status">status</a><br>
|
|
Status des Dienstes abrufen<br>
|
|
identisch zu 'set status'
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-attr"></a>
|
|
<p><b>Attribute</b></p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-attr-serviceAutostart">serviceAutostart</a><br>
|
|
Verzögerung in Sekunden um den Dienst nach Start von FHEM (neu) zu starten<br>
|
|
Voreinstellung:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceAutostop">serviceAutostop</a><br>
|
|
Timeout in Sekunden um den Dienst bei Beenden von FHEM ebenso zu beenden<br>
|
|
Voreinstellung:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceGetStatusOnInit">serviceGetStatusOnInit</a><br>
|
|
beim Start von FHEM automatisch den Status des Dienstes abrufen<br>
|
|
Voreinstellung: 1
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceInitd">serviceInitd</a><br>
|
|
benutze initd (system) statt systemd (systemctl)<br>
|
|
Voreinstellung: 0
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceLogin">serviceLogin</a><br>
|
|
SSH Anmeldedaten für entfernten Dienst<br>
|
|
passwortloser SSH Zugang ist Grundvoraussetzung<br>
|
|
Voreinstellung:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-servicePort">servicePort</a><br>
|
|
SSH Port falls ein anderer als der Standard Port (22) verwendet wird<br>
|
|
Voreinstellung: 22
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexFailed">serviceRegexFailed</a><br>
|
|
Regex für failed Status<br>
|
|
Voreinstellung: dead|failed|exited
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStarted">serviceRegexStarted</a><br>
|
|
Regex für running Status<br>
|
|
Voreinstellung: running|active
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStarting">serviceRegexStarting</a><br>
|
|
Regex für starting Status<br>
|
|
Voreinstellung: activating|starting
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceRegexStopped">serviceRegexStopped</a><br>
|
|
Regex für stopped Status<br>
|
|
Voreinstellung: inactive|stopped
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceStatusInterval">serviceStatusInterval</a><br>
|
|
Interval um den Status automatisch zu aktualisieren<br>
|
|
Voreinstellung:
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceStatusLine">serviceStatusLine</a><br>
|
|
Zeilennummer der Status Rückgabe welche die Status Information enthält<br>
|
|
Voreinstellung: 3
|
|
</li>
|
|
<li>
|
|
<a id="serviced-attr-serviceSudo">serviceSudo</a><br>
|
|
sudo benutzen<br>
|
|
Voreinstellung: 1
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<a id="serviced-read"></a>
|
|
<p><b>Readings</b></p>
|
|
<p>Alle Aktualisierungen der Readings erzeugen Events.</p>
|
|
<ul>
|
|
<li>
|
|
<a id="serviced-read-error">error</a><br>
|
|
letzter aufgetretener Fehler, none wenn kein Fehler aufgetreten ist
|
|
</li>
|
|
<li>
|
|
<a id="serviced-read-state">state</a><br>
|
|
aktueller Zustand
|
|
</li>
|
|
<li>
|
|
<a id="serviced-read-status">status</a><br>
|
|
letzte Statuszeile von 'get/set status'
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html_DE
|
|
=cut
|