mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-05 14:29:35 +00:00
49_SSCam(STRM): avoid possible warnings during FHEM shutdown/restart
git-svn-id: https://svn.fhem.de/fhem/trunk@22598 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
ef37fa8e56
commit
0973043db9
@ -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: 49_SSCam(STRM): avoid possible warnings during shutdown/restart
|
||||||
- bugfix: 52_I2C_HDC1008: fix "temperature" (broken by change from Aug, 1st)
|
- bugfix: 52_I2C_HDC1008: fix "temperature" (broken by change from Aug, 1st)
|
||||||
- feature: 49_SSCam: new attribute ptzNoCapPrePat
|
- feature: 49_SSCam: new attribute ptzNoCapPrePat
|
||||||
- feature: 60_Watches: control buttons,new attr hideButtons, controlButtonSize
|
- feature: 60_Watches: control buttons,new attr hideButtons, controlButtonSize
|
||||||
|
@ -159,6 +159,7 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"9.6.1" => "13.08.2020 avoid warnings during FHEM shutdown/restart ",
|
||||||
"9.6.0" => "12.08.2020 new attribute ptzNoCapPrePat ",
|
"9.6.0" => "12.08.2020 new attribute ptzNoCapPrePat ",
|
||||||
"9.5.3" => "27.07.2020 fix warning: Use of uninitialized value in subroutine dereference at ... ",
|
"9.5.3" => "27.07.2020 fix warning: Use of uninitialized value in subroutine dereference at ... ",
|
||||||
"9.5.2" => "26.07.2020 more changes according PBP level 3, minor fixes ",
|
"9.5.2" => "26.07.2020 more changes according PBP level 3, minor fixes ",
|
||||||
@ -472,11 +473,6 @@ my $valZoom = ".++,+,stop,-,--."; # Inhalt des Setters "
|
|||||||
#use vars qw($FW_room); # currently selected room
|
#use vars qw($FW_room); # currently selected room
|
||||||
#use vars qw($FW_detail); # currently selected device for detail view
|
#use vars qw($FW_detail); # currently selected device for detail view
|
||||||
#use vars qw($FW_wname); # Web instance
|
#use vars qw($FW_wname); # Web instance
|
||||||
# sub FW_pH(@); # add href
|
|
||||||
|
|
||||||
#sub SSChatBot_formString;
|
|
||||||
#sub SSChatBot_addQueue($$$$$$$$);
|
|
||||||
#sub SSChatBot_getapisites($);
|
|
||||||
|
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
# Hint Hash EN
|
# Hint Hash EN
|
||||||
@ -799,15 +795,13 @@ sub delayedShutdown {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
Log3($name, 2, "$name - Quit session due to shutdown ...");
|
Log3($name, 2, "$name - Quit session due to shutdown ...");
|
||||||
$hash->{HELPER}{ACTIVE} = "on"; # keine weiteren Aktionen erlauben
|
|
||||||
logout($hash);
|
sessionOff($hash);
|
||||||
|
|
||||||
if($hash->{HELPER}{CACHEKEY}) {
|
if($hash->{HELPER}{CACHEKEY}) {
|
||||||
cache($name, "c_destroy");
|
cache($name, "c_destroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete $data{SSCam}{$name}; # internen cache löschen
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,6 +828,8 @@ sub Delete {
|
|||||||
|
|
||||||
CommandDelete($hash->{CL},"TYPE=SSCamSTRM:FILTER=PARENT=$name"); # alle zugeordneten Streaming-Devices löschen falls vorhanden
|
CommandDelete($hash->{CL},"TYPE=SSCamSTRM:FILTER=PARENT=$name"); # alle zugeordneten Streaming-Devices löschen falls vorhanden
|
||||||
|
|
||||||
|
delete $data{SSCam}{$name}; # internen Cache löschen
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,7 +918,7 @@ sub Attr {
|
|||||||
if($hash->{HELPER}{CACHEKEY}) {
|
if($hash->{HELPER}{CACHEKEY}) {
|
||||||
cache($name, "c_destroy"); # CHI-Cache löschen/entfernen
|
cache($name, "c_destroy"); # CHI-Cache löschen/entfernen
|
||||||
} else {
|
} else {
|
||||||
delete $data{SSCam}{$name}; # internen Cache löschen
|
delete $data{SSCam}{$name}; # internen Cache löschen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4109,9 +4105,9 @@ return;
|
|||||||
# Session logout
|
# Session logout
|
||||||
###########################################################################
|
###########################################################################
|
||||||
sub sessionOff {
|
sub sessionOff {
|
||||||
my ($hash) = @_;
|
my $hash = shift;
|
||||||
my $camname = $hash->{CAMNAME};
|
my $camname = $hash->{CAMNAME};
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
RemoveInternalTimer($hash, "FHEM::SSCam::sessionOff");
|
RemoveInternalTimer($hash, "FHEM::SSCam::sessionOff");
|
||||||
return if(IsDisabled($name));
|
return if(IsDisabled($name));
|
||||||
@ -8012,13 +8008,13 @@ return;
|
|||||||
#
|
#
|
||||||
######################################################################################
|
######################################################################################
|
||||||
sub streamDev { ## no critic 'complexity'
|
sub streamDev { ## no critic 'complexity'
|
||||||
my $paref = shift;
|
my $paref = shift;
|
||||||
my $camname = $paref->{linkparent};
|
my $camname = $paref->{linkparent};
|
||||||
my $strmdev = $paref->{linkname};
|
my $strmdev = $paref->{linkname};
|
||||||
my $fmt = $paref->{linkmodel};
|
my $fmt = $paref->{linkmodel};
|
||||||
my $omodel = $paref->{omodel};
|
my $omodel = $paref->{omodel};
|
||||||
my $oname = $paref->{oname};
|
my $oname = $paref->{oname};
|
||||||
my $ftui = $paref->{ftui};
|
my $ftui = $paref->{ftui};
|
||||||
|
|
||||||
my $hash = $defs{$camname};
|
my $hash = $defs{$camname};
|
||||||
my $streamHash = $defs{$strmdev}; # Hash des SSCamSTRM-Devices
|
my $streamHash = $defs{$strmdev}; # Hash des SSCamSTRM-Devices
|
||||||
@ -8235,16 +8231,15 @@ return $ret;
|
|||||||
# Streaming Device Typ: mjpeg
|
# Streaming Device Typ: mjpeg
|
||||||
sub _streamDevMJPEG { ## no critic 'complexity not used'
|
sub _streamDevMJPEG { ## no critic 'complexity not used'
|
||||||
my $params = shift;
|
my $params = shift;
|
||||||
|
|
||||||
my $camname = $params->{camname};
|
my $camname = $params->{camname};
|
||||||
my $strmdev = $params->{strmdev};
|
my $strmdev = $params->{strmdev};
|
||||||
|
|
||||||
my $hash = $defs{$camname};
|
my $hash = $defs{$camname};
|
||||||
my $streamHash = $defs{$strmdev};
|
my $streamHash = $defs{$strmdev};
|
||||||
|
my $camid = $params->{camid} // return "";
|
||||||
|
my $sid = $params->{sid} // return "";
|
||||||
my $ftui = $params->{ftui};
|
my $ftui = $params->{ftui};
|
||||||
my $camid = $params->{camid};
|
|
||||||
my $proto = $params->{proto};
|
my $proto = $params->{proto};
|
||||||
my $sid = $params->{sid};
|
|
||||||
my $pws = $params->{pws};
|
my $pws = $params->{pws};
|
||||||
my $ha = $params->{ha};
|
my $ha = $params->{ha};
|
||||||
my $hb = $params->{hb};
|
my $hb = $params->{hb};
|
||||||
|
@ -91,6 +91,7 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"2.14.5" => "12.08.2020 avoid loose of adoption after restart ",
|
||||||
"2.14.4" => "03.08.2020 fix check of ARG in RemoveInternalTimer in _setadoptForTimer sub (sometimes no switch back done) ",
|
"2.14.4" => "03.08.2020 fix check of ARG in RemoveInternalTimer in _setadoptForTimer sub (sometimes no switch back done) ",
|
||||||
"2.14.3" => "01.08.2020 verbose 5 log in _setadoptForTimer sub ",
|
"2.14.3" => "01.08.2020 verbose 5 log in _setadoptForTimer sub ",
|
||||||
"2.14.2" => "29.07.2020 fix: adoptTime accept not only integer values ",
|
"2.14.2" => "29.07.2020 fix: adoptTime accept not only integer values ",
|
||||||
@ -232,7 +233,7 @@ sub Define {
|
|||||||
|
|
||||||
explodeLinkData ($hash, $link, 1);
|
explodeLinkData ($hash, $link, 1);
|
||||||
|
|
||||||
$hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden
|
$hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden
|
||||||
|
|
||||||
# Versionsinformationen setzen
|
# Versionsinformationen setzen
|
||||||
setVersionInfo($hash);
|
setVersionInfo($hash);
|
||||||
@ -624,7 +625,7 @@ sub FwFn {
|
|||||||
my $clink = ReadingsVal($name, "clientLink", "");
|
my $clink = ReadingsVal($name, "clientLink", "");
|
||||||
|
|
||||||
sofAdoptSubset ($hash);
|
sofAdoptSubset ($hash);
|
||||||
explodeLinkData ($hash, $clink, 0);
|
explodeLinkData ($hash, $clink, 0) if($init_done == 1);
|
||||||
|
|
||||||
# Beispielsyntax: "{$hash->{LINKFN}('$hash->{LINKPARENT}','$hash->{LINKNAME}','$hash->{LINKMODEL}')}";
|
# Beispielsyntax: "{$hash->{LINKFN}('$hash->{LINKPARENT}','$hash->{LINKNAME}','$hash->{LINKMODEL}')}";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
# $Id: 49_SSCam.pm 22481 2020-07-27 21:56:22Z DS_Starter $
|
# $Id: 49_SSCam.pm 22592 2020-08-12 21:28:56Z DS_Starter $
|
||||||
#########################################################################################################################
|
#########################################################################################################################
|
||||||
# 49_SSCam.pm
|
# 49_SSCam.pm
|
||||||
#
|
#
|
||||||
@ -159,7 +159,8 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
"9.6.0" => "11.08.2020 new attribute ptzNoCapPrePat ",
|
"9.6.1" => "13.08.2020 avoid warnings during FHEM shutdown/restart ",
|
||||||
|
"9.6.0" => "12.08.2020 new attribute ptzNoCapPrePat ",
|
||||||
"9.5.3" => "27.07.2020 fix warning: Use of uninitialized value in subroutine dereference at ... ",
|
"9.5.3" => "27.07.2020 fix warning: Use of uninitialized value in subroutine dereference at ... ",
|
||||||
"9.5.2" => "26.07.2020 more changes according PBP level 3, minor fixes ",
|
"9.5.2" => "26.07.2020 more changes according PBP level 3, minor fixes ",
|
||||||
"9.5.1" => "24.07.2020 set compatibility to 8.2.8, some changes according PBP level 3 ",
|
"9.5.1" => "24.07.2020 set compatibility to 8.2.8, some changes according PBP level 3 ",
|
||||||
@ -212,11 +213,13 @@ my %vNotesIntern = (
|
|||||||
|
|
||||||
# Versions History extern
|
# Versions History extern
|
||||||
my %vNotesExtern = (
|
my %vNotesExtern = (
|
||||||
|
"9.6.0" => "12.08.2020 The new attribute 'ptzNoCapPrePat' is available. It's helpfull if your PTZ camera doesn't have the capability ".
|
||||||
|
"to deliver Presets and Patrols. Setting the attribute avoid error log messages in that case. ",
|
||||||
"9.5.0" => "15.07.2020 A new type 'master' supplements the possible createStreamDev command options. The streaming type ".
|
"9.5.0" => "15.07.2020 A new type 'master' supplements the possible createStreamDev command options. The streaming type ".
|
||||||
"'master' cannot play back streams itself, but opens up new possibilities by flexibly accepting streams from ".
|
"'master' cannot play back streams itself, but opens up new possibilities by flexibly accepting streams from ".
|
||||||
"other defined streaming devices. ".
|
"other defined streaming devices. ".
|
||||||
"More information about the possibilities is described in this ".
|
"More information about the possibilities is described in this ".
|
||||||
"<a href=\"https://wiki.fhem.de/wiki/SSCAM_-_Steuerung_von_Kameras_in_Synology_Surveillance_Station#Das_Streaming_Master_Device_-_Typ_.22master.22\">Wiki article</a>. ",
|
"<a href=\"https://wiki.fhem.de/wiki/SSCAM_-_Steuerung_von_Kameras_in_Synology_Surveillance_Station#Das_Streaming_Master_Device_-_Typ_.22master.22\">Wiki article</a>. ",
|
||||||
"9.3.0" => "25.06.2020 Cameras with zoom function can also be controlled by FHEM. With the setter \"setZoom\", the zoom in/out ".
|
"9.3.0" => "25.06.2020 Cameras with zoom function can also be controlled by FHEM. With the setter \"setZoom\", the zoom in/out ".
|
||||||
"can be triggered in two steps. In the PTZ streaming device or FTUI, pushbuttons are provided for this purpose.",
|
"can be triggered in two steps. In the PTZ streaming device or FTUI, pushbuttons are provided for this purpose.",
|
||||||
"9.1.0" => "10.12.2019 With the new attribute \"snapChatTxt\" it is possible to send snapshots by the Synology Chat server. ".
|
"9.1.0" => "10.12.2019 With the new attribute \"snapChatTxt\" it is possible to send snapshots by the Synology Chat server. ".
|
||||||
@ -234,7 +237,7 @@ my %vNotesExtern = (
|
|||||||
"8.14.0" => "01.06.2019 In detailview are buttons provided to open the camera native setup screen or Synology Surveillance Station and the Synology Surveillance Station online help. ",
|
"8.14.0" => "01.06.2019 In detailview are buttons provided to open the camera native setup screen or Synology Surveillance Station and the Synology Surveillance Station online help. ",
|
||||||
"8.12.0" => "25.03.2019 Delay FHEM shutdown as long as sessions are not terminated, but not longer than global attribute \"maxShutdownDelay\". ",
|
"8.12.0" => "25.03.2019 Delay FHEM shutdown as long as sessions are not terminated, but not longer than global attribute \"maxShutdownDelay\". ",
|
||||||
"8.11.0" => "25.02.2019 compatibility set to SVS version 8.2.3, Popup possible for streaming devices of type \"generic\", ".
|
"8.11.0" => "25.02.2019 compatibility set to SVS version 8.2.3, Popup possible for streaming devices of type \"generic\", ".
|
||||||
"support for \"genericStrmHtmlTag\" in streaming devices ",
|
"support for \"genericStrmHtmlTag\" in streaming devices ",
|
||||||
"8.10.0" => "15.02.2019 Possibility of send recordings by telegram is integrated as well as sending snapshots ",
|
"8.10.0" => "15.02.2019 Possibility of send recordings by telegram is integrated as well as sending snapshots ",
|
||||||
"8.9.0" => "05.02.2019 A new streaming device type \"lastsnap\" was implemented. You can create such device with \"set ... createStreamDev lastsnap\". ".
|
"8.9.0" => "05.02.2019 A new streaming device type \"lastsnap\" was implemented. You can create such device with \"set ... createStreamDev lastsnap\". ".
|
||||||
"This streaming device shows the newest snapshot which was taken. ",
|
"This streaming device shows the newest snapshot which was taken. ",
|
||||||
@ -470,11 +473,6 @@ my $valZoom = ".++,+,stop,-,--."; # Inhalt des Setters "
|
|||||||
#use vars qw($FW_room); # currently selected room
|
#use vars qw($FW_room); # currently selected room
|
||||||
#use vars qw($FW_detail); # currently selected device for detail view
|
#use vars qw($FW_detail); # currently selected device for detail view
|
||||||
#use vars qw($FW_wname); # Web instance
|
#use vars qw($FW_wname); # Web instance
|
||||||
# sub FW_pH(@); # add href
|
|
||||||
|
|
||||||
#sub SSChatBot_formString;
|
|
||||||
#sub SSChatBot_addQueue($$$$$$$$);
|
|
||||||
#sub SSChatBot_getapisites($);
|
|
||||||
|
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
# Hint Hash EN
|
# Hint Hash EN
|
||||||
@ -797,15 +795,13 @@ sub delayedShutdown {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
Log3($name, 2, "$name - Quit session due to shutdown ...");
|
Log3($name, 2, "$name - Quit session due to shutdown ...");
|
||||||
$hash->{HELPER}{ACTIVE} = "on"; # keine weiteren Aktionen erlauben
|
|
||||||
logout($hash);
|
sessionOff($hash);
|
||||||
|
|
||||||
if($hash->{HELPER}{CACHEKEY}) {
|
if($hash->{HELPER}{CACHEKEY}) {
|
||||||
cache($name, "c_destroy");
|
cache($name, "c_destroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete $data{SSCam}{$name}; # internen cache löschen
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -832,6 +828,8 @@ sub Delete {
|
|||||||
|
|
||||||
CommandDelete($hash->{CL},"TYPE=SSCamSTRM:FILTER=PARENT=$name"); # alle zugeordneten Streaming-Devices löschen falls vorhanden
|
CommandDelete($hash->{CL},"TYPE=SSCamSTRM:FILTER=PARENT=$name"); # alle zugeordneten Streaming-Devices löschen falls vorhanden
|
||||||
|
|
||||||
|
delete $data{SSCam}{$name}; # internen Cache löschen
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,7 +918,7 @@ sub Attr {
|
|||||||
if($hash->{HELPER}{CACHEKEY}) {
|
if($hash->{HELPER}{CACHEKEY}) {
|
||||||
cache($name, "c_destroy"); # CHI-Cache löschen/entfernen
|
cache($name, "c_destroy"); # CHI-Cache löschen/entfernen
|
||||||
} else {
|
} else {
|
||||||
delete $data{SSCam}{$name}; # internen Cache löschen
|
delete $data{SSCam}{$name}; # internen Cache löschen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4107,9 +4105,9 @@ return;
|
|||||||
# Session logout
|
# Session logout
|
||||||
###########################################################################
|
###########################################################################
|
||||||
sub sessionOff {
|
sub sessionOff {
|
||||||
my ($hash) = @_;
|
my $hash = shift;
|
||||||
my $camname = $hash->{CAMNAME};
|
my $camname = $hash->{CAMNAME};
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
RemoveInternalTimer($hash, "FHEM::SSCam::sessionOff");
|
RemoveInternalTimer($hash, "FHEM::SSCam::sessionOff");
|
||||||
return if(IsDisabled($name));
|
return if(IsDisabled($name));
|
||||||
@ -8010,13 +8008,13 @@ return;
|
|||||||
#
|
#
|
||||||
######################################################################################
|
######################################################################################
|
||||||
sub streamDev { ## no critic 'complexity'
|
sub streamDev { ## no critic 'complexity'
|
||||||
my $paref = shift;
|
my $paref = shift;
|
||||||
my $camname = $paref->{linkparent};
|
my $camname = $paref->{linkparent};
|
||||||
my $strmdev = $paref->{linkname};
|
my $strmdev = $paref->{linkname};
|
||||||
my $fmt = $paref->{linkmodel};
|
my $fmt = $paref->{linkmodel};
|
||||||
my $omodel = $paref->{omodel};
|
my $omodel = $paref->{omodel};
|
||||||
my $oname = $paref->{oname};
|
my $oname = $paref->{oname};
|
||||||
my $ftui = $paref->{ftui};
|
my $ftui = $paref->{ftui};
|
||||||
|
|
||||||
my $hash = $defs{$camname};
|
my $hash = $defs{$camname};
|
||||||
my $streamHash = $defs{$strmdev}; # Hash des SSCamSTRM-Devices
|
my $streamHash = $defs{$strmdev}; # Hash des SSCamSTRM-Devices
|
||||||
@ -8233,16 +8231,15 @@ return $ret;
|
|||||||
# Streaming Device Typ: mjpeg
|
# Streaming Device Typ: mjpeg
|
||||||
sub _streamDevMJPEG { ## no critic 'complexity not used'
|
sub _streamDevMJPEG { ## no critic 'complexity not used'
|
||||||
my $params = shift;
|
my $params = shift;
|
||||||
|
|
||||||
my $camname = $params->{camname};
|
my $camname = $params->{camname};
|
||||||
my $strmdev = $params->{strmdev};
|
my $strmdev = $params->{strmdev};
|
||||||
|
|
||||||
my $hash = $defs{$camname};
|
my $hash = $defs{$camname};
|
||||||
my $streamHash = $defs{$strmdev};
|
my $streamHash = $defs{$strmdev};
|
||||||
|
my $camid = $params->{camid} // return "";
|
||||||
|
my $sid = $params->{sid} // return "";
|
||||||
my $ftui = $params->{ftui};
|
my $ftui = $params->{ftui};
|
||||||
my $camid = $params->{camid};
|
|
||||||
my $proto = $params->{proto};
|
my $proto = $params->{proto};
|
||||||
my $sid = $params->{sid};
|
|
||||||
my $pws = $params->{pws};
|
my $pws = $params->{pws};
|
||||||
my $ha = $params->{ha};
|
my $ha = $params->{ha};
|
||||||
my $hb = $params->{hb};
|
my $hb = $params->{hb};
|
||||||
@ -11437,12 +11434,12 @@ sub setVersionInfo {
|
|||||||
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) {
|
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) {
|
||||||
# META-Daten sind vorhanden
|
# META-Daten sind vorhanden
|
||||||
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}}
|
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}}
|
||||||
if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCam.pm 22481 2020-07-27 21:56:22Z DS_Starter $ im Kopf komplett! vorhanden )
|
if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCam.pm 22592 2020-08-12 21:28:56Z DS_Starter $ im Kopf komplett! vorhanden )
|
||||||
$modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx;
|
$modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx;
|
||||||
} else {
|
} else {
|
||||||
$modules{$type}{META}{x_version} = $v;
|
$modules{$type}{META}{x_version} = $v;
|
||||||
}
|
}
|
||||||
return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCam.pm 22481 2020-07-27 21:56:22Z DS_Starter $ im Kopf komplett! vorhanden )
|
return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCam.pm 22592 2020-08-12 21:28:56Z DS_Starter $ im Kopf komplett! vorhanden )
|
||||||
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) {
|
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) {
|
||||||
# es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
|
# es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
|
||||||
# mit {<Modul>->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
|
# mit {<Modul>->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
# $Id: 49_SSCamSTRM.pm 22446 2020-07-20 21:16:31Z DS_Starter $
|
# $Id: 49_SSCamSTRM.pm 22534 2020-08-03 20:10:28Z DS_Starter $
|
||||||
#########################################################################################################################
|
#########################################################################################################################
|
||||||
# 49_SSCamSTRM.pm
|
# 49_SSCamSTRM.pm
|
||||||
#
|
#
|
||||||
@ -47,6 +47,7 @@ BEGIN {
|
|||||||
defs
|
defs
|
||||||
devspec2array
|
devspec2array
|
||||||
FmtDateTime
|
FmtDateTime
|
||||||
|
init_done
|
||||||
InternalTimer
|
InternalTimer
|
||||||
IsDisabled
|
IsDisabled
|
||||||
Log3
|
Log3
|
||||||
@ -90,6 +91,12 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"2.14.5" => "12.08.2020 avoid loose of adoption after restart ",
|
||||||
|
"2.14.4" => "03.08.2020 fix check of ARG in RemoveInternalTimer in _setadoptForTimer sub (sometimes no switch back done) ",
|
||||||
|
"2.14.3" => "01.08.2020 verbose 5 log in _setadoptForTimer sub ",
|
||||||
|
"2.14.2" => "29.07.2020 fix: adoptTime accept not only integer values ",
|
||||||
|
"2.14.1" => "28.07.2020 switching time increases with each adoptForTimer command ",
|
||||||
|
"2.14.0" => "27.07.2020 new commands adoptForTimer and control command adoptTime ",
|
||||||
"2.13.1" => "21.07.2020 fix: set of values in attr adoptSubset is empty after restart, changes according level 3 PBP ",
|
"2.13.1" => "21.07.2020 fix: set of values in attr adoptSubset is empty after restart, changes according level 3 PBP ",
|
||||||
"2.13.0" => "14.07.2020 integrate streamDev master ",
|
"2.13.0" => "14.07.2020 integrate streamDev master ",
|
||||||
"2.12.0" => "28.06.2020 upgrade SSCam functions due to SSCam switch to packages ",
|
"2.12.0" => "28.06.2020 upgrade SSCam functions due to SSCam switch to packages ",
|
||||||
@ -154,9 +161,11 @@ my %hvattr = ( # Has
|
|||||||
);
|
);
|
||||||
|
|
||||||
my %hset = ( # Hash für Set-Funktion
|
my %hset = ( # Hash für Set-Funktion
|
||||||
popupStream => { fn => "_setpopupStream" },
|
popupStream => { fn => "_setpopupStream" },
|
||||||
adopt => { fn => "_setadopt" },
|
adopt => { fn => "_setadopt" },
|
||||||
reset => { fn => "_setreset" },
|
adoptForTimer => { fn => "_setadoptForTimer" },
|
||||||
|
adoptTime => { fn => "_setAdoptTimer" },
|
||||||
|
reset => { fn => "_setreset" },
|
||||||
);
|
);
|
||||||
|
|
||||||
my %sdevs = (); # Hash der vorhandenen Streaming Devices
|
my %sdevs = (); # Hash der vorhandenen Streaming Devices
|
||||||
@ -224,7 +233,7 @@ sub Define {
|
|||||||
|
|
||||||
explodeLinkData ($hash, $link, 1);
|
explodeLinkData ($hash, $link, 1);
|
||||||
|
|
||||||
$hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden
|
$hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden
|
||||||
|
|
||||||
# Versionsinformationen setzen
|
# Versionsinformationen setzen
|
||||||
setVersionInfo($hash);
|
setVersionInfo($hash);
|
||||||
@ -304,12 +313,14 @@ sub Set {
|
|||||||
$sd =~ s/\s+/#/gx;
|
$sd =~ s/\s+/#/gx;
|
||||||
|
|
||||||
my $rsd = $as;
|
my $rsd = $as;
|
||||||
$rsd =~ s/#/ /g; ## no critic 'regular expression' # Regular expression without "/x" flag nicht anwenden !!!
|
$rsd =~ s/#/ /g; ## no critic 'regular expression' # Regular expression without "/x" flag nicht anwenden !!!
|
||||||
push my @ado, "adoptList:$rsd";
|
push my @ado, "adoptList:$rsd";
|
||||||
setReadings($hash, \@ado, 0);
|
setReadings($hash, \@ado, 0);
|
||||||
|
|
||||||
$setlist = "Unknown argument $opt, choose one of ".
|
$setlist = "Unknown argument $opt, choose one of ".
|
||||||
"adopt:$sd "
|
"adopt:$sd ".
|
||||||
|
"adoptForTimer:$sd ".
|
||||||
|
"adoptTime "
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,8 +334,9 @@ sub Set {
|
|||||||
|
|
||||||
no strict "refs"; ## no critic 'NoStrict'
|
no strict "refs"; ## no critic 'NoStrict'
|
||||||
if($hset{$opt}) {
|
if($hset{$opt}) {
|
||||||
&{$hset{$opt}{fn}} (\%params) if(defined &{$hset{$opt}{fn}});
|
my $ret = "";
|
||||||
return;
|
$ret = &{$hset{$opt}{fn}} (\%params) if(defined &{$hset{$opt}{fn}});
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
use strict "refs";
|
use strict "refs";
|
||||||
|
|
||||||
@ -423,6 +435,84 @@ sub _setadopt { ## no critic "not used"
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# setter adopt-for-timer
|
||||||
|
# schaltet für eine bestimmte Zeit auf das ausgewählte
|
||||||
|
# Streaming Device und wieder auf das vorherige zurück
|
||||||
|
###############################################################
|
||||||
|
sub _setadoptForTimer { ## no critic "not used"
|
||||||
|
my $paref = shift;
|
||||||
|
my $hash = $paref->{hash};
|
||||||
|
my $name = $paref->{name};
|
||||||
|
my $opt = $paref->{opt};
|
||||||
|
my $odev = $paref->{odev}; # bisheriges adoptiertes Device (wird erst im InternalTimer gesetzt und verwendet)
|
||||||
|
|
||||||
|
return if(IsDisabled($name) || $init_done != 1);
|
||||||
|
|
||||||
|
my $sdev;
|
||||||
|
my $atime = ReadingsVal($name, "adoptTimer", 10);
|
||||||
|
|
||||||
|
if(!$odev) { # Step 1 -> erster Durchlauf ohne odef
|
||||||
|
$hash->{HELPER}{SWITCHED} = $hash->{LINKNAME} if(!$hash->{HELPER}{SWITCHED});
|
||||||
|
$paref->{odev} = $hash->{HELPER}{SWITCHED}; # bisheriges adoptiertes Device in %params aufnehmen, InternalTimer mitgeben
|
||||||
|
|
||||||
|
} else { # Step 2 -> zweiter Durchlauf mit odef gesetzt
|
||||||
|
my @a;
|
||||||
|
delete $hash->{HELPER}{SWITCHED};
|
||||||
|
$sdev = $odev eq $name ? "--reset--" : $odev;
|
||||||
|
|
||||||
|
push @a, $name;
|
||||||
|
push @a, $opt;
|
||||||
|
push @a, $sdev;
|
||||||
|
|
||||||
|
$paref->{aref} = \@a;
|
||||||
|
}
|
||||||
|
|
||||||
|
no strict "refs"; ## no critic 'NoStrict'
|
||||||
|
&{$hset{adopt}{fn}} ($paref);
|
||||||
|
use strict "refs";
|
||||||
|
|
||||||
|
Log3($name, 5, "$name - new => $hash->{LINKNAME}, odev => ".($odev // "")." , sdev => ".($sdev // "")." ,Helper SWITCHED => ".($hash->{HELPER}{SWITCHED} // "").", switch time => $atime");
|
||||||
|
|
||||||
|
if($odev) {
|
||||||
|
Log3($name, 4, qq{$name - Switched Stream Device back to "$sdev"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3($name, 4, qq{$name - Switched to Stream Device "$hash->{LINKNAME}" for $atime seconds});
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash->{HELPER}{ARG}, "FHEM::SSCamSTRM::_setadoptForTimer");
|
||||||
|
$hash->{HELPER}{ARG} = $paref; # $paref ist Unikat !
|
||||||
|
InternalTimer(gettimeofday()+$atime, "FHEM::SSCamSTRM::_setadoptForTimer", $paref, 0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Setter adoptTimer
|
||||||
|
# setzt die Schaltzeit für setter adoptForTimer
|
||||||
|
################################################################
|
||||||
|
sub _setAdoptTimer { ## no critic "not used"
|
||||||
|
my $paref = shift;
|
||||||
|
my $hash = $paref->{hash};
|
||||||
|
my $opt = $paref->{opt};
|
||||||
|
my $prop = $paref->{prop} // 0;
|
||||||
|
|
||||||
|
my $ret = "";
|
||||||
|
$ret = qq{The command "$opt" needs an integer as argument.} if($prop !~ /^[0-9]+?$/x);
|
||||||
|
return $ret if($ret);
|
||||||
|
|
||||||
|
delReadings ($hash, "adoptTimer");
|
||||||
|
|
||||||
|
if($prop) { # bei "0" wird das Reading nur gelöscht, nicht wieder gesetzt
|
||||||
|
my @r;
|
||||||
|
push @r, "adoptTimer:$prop";
|
||||||
|
|
||||||
|
setReadings($hash, \@r, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Setter reset
|
# Setter reset
|
||||||
@ -535,7 +625,7 @@ sub FwFn {
|
|||||||
my $clink = ReadingsVal($name, "clientLink", "");
|
my $clink = ReadingsVal($name, "clientLink", "");
|
||||||
|
|
||||||
sofAdoptSubset ($hash);
|
sofAdoptSubset ($hash);
|
||||||
explodeLinkData ($hash, $clink, 0);
|
explodeLinkData ($hash, $clink, 0) if($init_done == 1);
|
||||||
|
|
||||||
# Beispielsyntax: "{$hash->{LINKFN}('$hash->{LINKPARENT}','$hash->{LINKNAME}','$hash->{LINKMODEL}')}";
|
# Beispielsyntax: "{$hash->{LINKFN}('$hash->{LINKPARENT}','$hash->{LINKNAME}','$hash->{LINKMODEL}')}";
|
||||||
|
|
||||||
@ -667,12 +757,12 @@ sub setVersionInfo {
|
|||||||
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) {
|
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) {
|
||||||
# META-Daten sind vorhanden
|
# META-Daten sind vorhanden
|
||||||
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SSCamSTRM}{META}}
|
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SSCamSTRM}{META}}
|
||||||
if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22446 2020-07-20 21:16:31Z DS_Starter $ im Kopf komplett! vorhanden )
|
if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22534 2020-08-03 20:10:28Z DS_Starter $ im Kopf komplett! vorhanden )
|
||||||
$modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx;
|
$modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx;
|
||||||
} else {
|
} else {
|
||||||
$modules{$type}{META}{x_version} = $v;
|
$modules{$type}{META}{x_version} = $v;
|
||||||
}
|
}
|
||||||
return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22446 2020-07-20 21:16:31Z DS_Starter $ im Kopf komplett! vorhanden )
|
return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22534 2020-08-03 20:10:28Z DS_Starter $ im Kopf komplett! vorhanden )
|
||||||
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) {
|
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) {
|
||||||
# es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
|
# es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
|
||||||
# mit {<Modul>->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
|
# mit {<Modul>->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
|
||||||
@ -736,29 +826,6 @@ sub streamAsHtml {
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
|
||||||
# delete Readings
|
|
||||||
# $rd = angegebenes Reading löschen
|
|
||||||
################################################################
|
|
||||||
sub delReadings {
|
|
||||||
my $hash = shift;
|
|
||||||
my $rd = shift;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
|
|
||||||
my $bl = "state|parentState|adoptSubset"; # Blacklist
|
|
||||||
|
|
||||||
if($rd) { # angegebenes Reading löschen wenn nicht im providerLevel enthalten
|
|
||||||
readingsDelete($hash, $rd) if($rd !~ /$bl/x);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $key (keys %{$hash->{READINGS}}) {
|
|
||||||
readingsDelete($hash, $key) if($key !~ /$bl/x);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Wertevorrat für adoptSubset generieren
|
# Wertevorrat für adoptSubset generieren
|
||||||
################################################################
|
################################################################
|
||||||
@ -806,6 +873,30 @@ sub setReadings {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# delete Readings
|
||||||
|
# $rd = angegebenes Reading löschen unabhängig vom
|
||||||
|
# Inhalt der Blacklist
|
||||||
|
################################################################
|
||||||
|
sub delReadings {
|
||||||
|
my $hash = shift;
|
||||||
|
my $rd = shift;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
my $bl = "state|parentState|adoptSubset|adoptTimer"; # Blacklist
|
||||||
|
|
||||||
|
if($rd) { # angegebenes Reading löschen
|
||||||
|
readingsDelete($hash, $rd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $key (keys %{$hash->{READINGS}}) {
|
||||||
|
readingsDelete($hash, $key) if($key !~ /$bl/x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# liefert String aller Streamingdevices außer MODEL = master
|
# liefert String aller Streamingdevices außer MODEL = master
|
||||||
# und füllt Hash %sdevs{Alias} = Devicename zu Auflösung
|
# und füllt Hash %sdevs{Alias} = Devicename zu Auflösung
|
||||||
@ -941,6 +1032,38 @@ return $ret;
|
|||||||
<b>Set</b>
|
<b>Set</b>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adopt"></a>
|
||||||
|
<li><b>adopt <Streaming device> </b> (only valid if MODEL = master)<br>
|
||||||
|
|
||||||
|
A Streaming Device of type <b>master</b> adopts the content of another defined Streaming Device.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adoptForTimer"></a>
|
||||||
|
<li><b>adoptForTimer <Streaming Device> </b> (only valid if MODEL = master)<br>
|
||||||
|
|
||||||
|
A Streaming Device of type <b>master</b> adopts the content of another defined Streaming Device
|
||||||
|
for a certain time. <br>
|
||||||
|
The time is set with the command <b>set <name> adoptTime</b>. <br>
|
||||||
|
(default: 10 seconds)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adoptTime"></a>
|
||||||
|
<li><b>adoptTime <seconds> </b> (only valid if MODEL = master)<br>
|
||||||
|
|
||||||
|
Setting of the switching time when temporarily taking over the content of another Streaming Device.
|
||||||
|
After the time has expired, playback is switched back to the previously set Streaming Device. <br>
|
||||||
|
If no argument or "0" is given, the time specification is deleted and the default (10 seconds) is used.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>popupStream</b> (only valid if MODEL != master)<br>
|
<li><b>popupStream</b> (only valid if MODEL != master)<br>
|
||||||
|
|
||||||
@ -953,14 +1076,6 @@ return $ret;
|
|||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><b>adopt <Streaming device> </b> (only valid if MODEL = master)<br>
|
|
||||||
|
|
||||||
A Streaming Device of type <b>master</b> adopts the content of another defined Streaming Device.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@ -1203,6 +1318,38 @@ attr <name> genericStrmHtmlTag <img $HTMLATTR
|
|||||||
<b>Set</b>
|
<b>Set</b>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adopt"></a>
|
||||||
|
<li><b>adopt <Streaming Device> </b> (nur wenn MODEL = master)<br>
|
||||||
|
|
||||||
|
Ein Streaming Device vom Type <b>master</b> übernimmt (adoptiert) den Content eines anderen definierten Streaming Devices.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adoptForTimer"></a>
|
||||||
|
<li><b>adoptForTimer <Streaming Device> </b> (nur wenn MODEL = master)<br>
|
||||||
|
|
||||||
|
Ein Streaming Device vom Type <b>master</b> übernimmt (adoptiert) den Content eines anderen definierten Streaming Devices
|
||||||
|
für eine bestimmte Zeit. <br>
|
||||||
|
Die Zeit wird mit dem Kommando <b>set <name> adoptTime</b> eingestellt. <br>
|
||||||
|
(default: 10 Sekunden)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<a name="adoptTime"></a>
|
||||||
|
<li><b>adoptTime <Sekunden> </b> (nur wenn MODEL = master)<br>
|
||||||
|
|
||||||
|
Einstellung der Schaltzeit bei temporärer Übernahme des Contents eines anderen Streaming Devices.
|
||||||
|
Nach Ablauf der Zeit wird die Wiedergabe auf das vorher eingestellte Streaming Device zurückgeschaltet. <br>
|
||||||
|
Wird kein Argument oder "0" angegeben, wird die Zeitvorgabe gelöscht und der Standard (10 Sekunden) verwendet.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>popupStream [OK | <Sekunden>]</b> (nur wenn MODEL != master)<br>
|
<li><b>popupStream [OK | <Sekunden>]</b> (nur wenn MODEL != master)<br>
|
||||||
|
|
||||||
@ -1216,14 +1363,6 @@ attr <name> genericStrmHtmlTag <img $HTMLATTR
|
|||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><b>adopt <Streaming Device> </b> (nur wenn MODEL = master)<br>
|
|
||||||
|
|
||||||
Ein Streaming Device vom Type <b>master</b> übernimmt (adoptiert) den Content eines anderen definierten Streaming Devices.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user