mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
many changes: (patch von Beta-User)
git-svn-id: https://svn.fhem.de/fhem/trunk@23653 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
92fed7e658
commit
6007a0cc96
@ -33,6 +33,10 @@
|
||||
# 31.01.2021 1.3.1
|
||||
# cleanup : Bereinigung der Konstruktionen wie my $... if / unless ...
|
||||
# (patch von Beta-User)
|
||||
# bugfix : retain bei MQTT2 ohne Funktion (patch von Beta-User)
|
||||
# added : Initialisierung beim Start für AttrTemplate (patch von Beta-User)
|
||||
# added : Unterstützung für Attribut forceNEXT (patch von Beta-User)
|
||||
# cleanup : Dokumentation (patch von Beta-User)
|
||||
#
|
||||
# 19.01.2021 1.3.0
|
||||
# feature : supports attrTemplate (thanks to Beta-User)
|
||||
@ -446,6 +450,7 @@ sub MQTT_GENERIC_BRIDGE_Initialize($) {
|
||||
CTRL_ATTR_NAME_GLOBAL_DEV_EXCLUDE.":textField-long ".
|
||||
"disable:1,0 ".
|
||||
"debug:0,1 ".
|
||||
"forceNEXT:0,1 ".
|
||||
$main::readingFnAttributes;
|
||||
|
||||
#main::LoadModule("MQTT");
|
||||
@ -656,6 +661,7 @@ sub Define() {
|
||||
# $hash->{subscribeExpr} = [];
|
||||
# }
|
||||
|
||||
::AttrTemplate_Initialize() if $::init_done;
|
||||
# noetig hier beim Anlegen im laufendem Betrieb
|
||||
InternalTimer(1, \&firstInit, $hash);
|
||||
|
||||
@ -2460,7 +2466,7 @@ sub doPublish($$$$$$$$) {
|
||||
if (isIODevMQTT2($hash)){ #if ($hash->{+HELPER}->{+IO_DEV_TYPE} eq 'MQTT2_SERVER') {
|
||||
# TODO: publish MQTT2
|
||||
# TODO qos / retain ?
|
||||
$topic.=':r' if $retain;
|
||||
$topic ='-r $topic' if $retain;
|
||||
IOWrite($hash, "publish", $topic.' '.$message);
|
||||
readingsSingleUpdate($hash,"transmission-state","outgoing publish sent",1);
|
||||
$hash->{+HELPER}->{+HS_PROP_NAME_OUTGOING_CNT}++;
|
||||
@ -2821,6 +2827,7 @@ sub Parse($$) {
|
||||
|
||||
my @instances = devspec2array("TYPE=MQTT_GENERIC_BRIDGE");
|
||||
my @ret=();
|
||||
my $forceNext = 0;
|
||||
foreach my $dev (@instances) {
|
||||
my $hash = $defs{$dev};
|
||||
# Name mit IODev vegleichen
|
||||
@ -2841,6 +2848,7 @@ sub Parse($$) {
|
||||
next unless defined $fret;
|
||||
if( ref($fret) eq 'ARRAY' ) {
|
||||
push (@ret, @{$fret});
|
||||
$forceNext = 1 if AttrVal($hash->{NAME},'forceNEXT',0);
|
||||
#my @ret=@{$fret};
|
||||
#unshift(@ret, "[NEXT]"); # damit weitere Geraetemodule ggf. aufgerufen werden
|
||||
#return @ret;
|
||||
@ -2848,7 +2856,7 @@ sub Parse($$) {
|
||||
Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE: [$hash->{NAME}] Parse ($iiodt : '$ioname'): internal error: onmessage returned an unexpected value: ".$fret);
|
||||
}
|
||||
}
|
||||
unshift(@ret, "[NEXT]"); # damit weitere Geraetemodule ggf. aufgerufen werden
|
||||
unshift(@ret, "[NEXT]") if !(@ret) || $forceNext; # damit weitere Geraetemodule ggf. aufgerufen werden
|
||||
return @ret;
|
||||
}
|
||||
|
||||
@ -2946,6 +2954,7 @@ sub onmessage($$$) {
|
||||
1;
|
||||
|
||||
=pod
|
||||
=encoding utf8
|
||||
=item [device]
|
||||
=item summary MQTT_GENERIC_BRIDGE acts as a bridge for any fhem-devices and mqtt-topics
|
||||
=begin html
|
||||
@ -3066,13 +3075,6 @@ sub onmessage($$$) {
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>globalSubscribe ! TODO - is currently not supported and may not be implemented at all!<br/>
|
||||
Defines topics / flags for MQTT transmission. These are used if there are no suitable values in the respective device.
|
||||
see <a href="#MQTT_GENERIC_BRIDGEmqttSubscribe">mqttSubscribe</a>.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>globalTypeExclude<br/>
|
||||
Defines (device) types and readings that should not be considered in the transmission.
|
||||
@ -3095,6 +3097,12 @@ sub onmessage($$$) {
|
||||
<p>Example:<br/>
|
||||
<code>attr <dev> globalDeviceExclude Test Bridge:transmission-state</code></p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>forceNEXT<br/>
|
||||
Only relevant for MQTT2_CLIENT or MQTT2_SERVER as IODev. If set to 1, MQTT_GENERIC_BRIDGE will forward incoming messages also to further client modules like MQTT2_DEVICE, even if the topic matches to one of the subscriptions of the controlled devices. By default, these messages will not be forwarded for better compability with autocreate feature on MQTT2_DEVICE. See also <a href="#MQTT2_CLIENTclientOrder">clientOrder attribute in MQTT2 IO-type commandrefs</a>; setting this in one instance of MQTT_GENERIC _BRIDGE might affect others, too.</p>
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<p>For the monitored devices, a list of the possible attributes is automatically extended by several further entries.
|
||||
They all begin with a prefix previously defined in the bridge. These attributes are used to configure the actual MQTT mapping.<br/>
|
||||
@ -3349,13 +3357,13 @@ sub onmessage($$$) {
|
||||
<h3>MQTT_GENERIC_BRIDGE</h3>
|
||||
<ul>
|
||||
<p>
|
||||
Dieses Modul ist eine MQTT-Bridge, die gleichzeitig mehrere FHEM-Devices erfasst und deren Readings
|
||||
per MQTT weiter gibt bzw. aus den eintreffenden MQTT-Nachrichten befuellt oder diese als 'set'-Befehl
|
||||
an dem konfigurierten FHEM-Geraet ausfuert.
|
||||
<br/>Es wird eines der folgenden Geraete als IODev benoetigt: <a href="#MQTT">MQTT</a>,
|
||||
Dieses Modul ist eine MQTT-Bridge, die gleichzeitig mehrere FHEM-Devices erfaßt und deren Readings
|
||||
per MQTT weiter gibt bzw. aus den eintreffenden MQTT-Nachrichten befüllt oder diese als 'set'-Befehl
|
||||
an dem konfigurierten FHEM-Gerät ausführt.
|
||||
<br/>Es wird eines der folgenden Geräte als IODev benötigt: <a href="#MQTT">MQTT</a>,
|
||||
<a href="#MQTT2_CLIENT">MQTT2_CLIENT</a> oder <a href="#MQTT2_SERVER">MQTT2_SERVER</a>.
|
||||
</p>
|
||||
<p>Die (minimale) Konfiguration der Bridge selbst ist grundsaetzlich sehr einfach.</p>
|
||||
<p>Die (minimale) Konfiguration der Bridge selbst ist grundsätzlich sehr einfach.</p>
|
||||
<a name="MQTT_GENERIC_BRIDGEdefine"></a>
|
||||
<p><b>Definition:</b></p>
|
||||
<ul>
|
||||
@ -3363,13 +3371,13 @@ sub onmessage($$$) {
|
||||
<p><code>defmod mqttGeneric MQTT_GENERIC_BRIDGE [prefix] [devspec,[devspec]]</br>
|
||||
attr mqttGeneric IODev <MQTT-Device></code></p>
|
||||
<p>Alle Parameter im Define sind optional.</p>
|
||||
<p>Der erste ist ein Prefix fuer die Steuerattribute, worueber die zu ueberwachende Geraete (s.u.)
|
||||
<p>Der erste ist ein Prefix für die Steuerattribute, worüber die zu ueberwachende Geraete (s.u.)
|
||||
konfiguriert werden. Defaultwert ist 'mqtt'.
|
||||
Wird dieser z.B. als 'hugo' redefiniert, heissen die Steuerungsattribute entsprechend hugoPublish etc.</p>
|
||||
<p>Der zweite Parameter ('devspec') erlaubt die Menge der zu ueberwachenden Geraeten
|
||||
zu begrenzen (sonst werden einfach alle ueberwacht, was jedoch Performance kosten kann).
|
||||
Beispiel fuer devspec: 'TYPE=dummy' oder 'dummy1,dummy2'. Bei kommaseparierten Liste duerfen keine Leerzeichen verwendet werden!
|
||||
s.a. <a href="https://fhem.de/commandref_DE.html#devspec">devspec</a></p>
|
||||
Wird dieser z.B. als 'mqttGB1_' festgelegt, heißen die Steuerungsattribute entsprechend mqttGB1_Publish etc.</p>
|
||||
<p>Der zweite Parameter ('devspec') erlaubt die Menge der zu überwachenden Geraeten
|
||||
zu begrenzen (sonst werden einfach alle überwacht, was jedoch Performance kosten kann).
|
||||
Beispiel fuer devspec: 'TYPE=dummy' oder 'dummy1,dummy2'. Bei kommaseparierten Liste dürfen keine Leerzeichen verwendet werden!
|
||||
s.a. <a href="#devspec">devspec</a></p>
|
||||
</ul>
|
||||
|
||||
<a name="MQTT_GENERIC_BRIDGEget"></a>
|
||||
@ -3381,14 +3389,14 @@ sub onmessage($$$) {
|
||||
</li>
|
||||
<li>
|
||||
<p>devlist [<name (regex)>]<br/>
|
||||
Liefert Liste der Namen der von dieser Bridge ueberwachten Geraete deren Namen zu dem optionalen regulaerem Ausdruck entsprechen.
|
||||
Liefert Liste der Namen der von dieser Bridge überwachten Geräte deren Namen zu dem optionalen regulaerem Ausdruck entsprechen.
|
||||
Fehlt der Ausdruck, werden alle Geraete aufgelistet.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>devinfo [<name (regex)>]<br/>
|
||||
Gibt eine Liste der ueberwachten Geraete aus, deren Namen dem optionalen regulaeren Ausdruck entsprechen.
|
||||
Fehlt der Ausdruck, werden alle Geraete aufgelistet. Zusaetzlich werden bei 'publish' und 'subscribe'
|
||||
Gibt eine Liste der überwachten Geräte aus, deren Namen dem optionalen regulären Ausdruck entsprechen.
|
||||
Fehlt der Ausdruck, werden alle Geräte aufgelistet. Zusätzlich werden bei 'publish' und 'subscribe'
|
||||
verwendete Topics angezeigt incl. der entsprechenden Readingsnamen.</p>
|
||||
</li>
|
||||
</ul>
|
||||
@ -3398,7 +3406,7 @@ sub onmessage($$$) {
|
||||
<ul>
|
||||
<li>
|
||||
<p>device-count<br/>
|
||||
Anzahl der ueberwachten Geraete</p>
|
||||
Anzahl der überwachten Geräte</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>incoming-count<br/>
|
||||
@ -3418,17 +3426,18 @@ sub onmessage($$$) {
|
||||
</li>
|
||||
<li>
|
||||
<p>transmission-state<br/>
|
||||
letze Uebertragunsart</p>
|
||||
letze Übertragunsart</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<a name="MQTT_GENERIC_BRIDGEattr"></a>
|
||||
<p><b>Attribute:</b></p>
|
||||
<ul>
|
||||
<p>folgende Attribute werden unterstuetzt:</p>
|
||||
<p>Folgende Attribute werden unterstützt:</p>
|
||||
<li><p><b>Im MQTT_GENERIC_BRIDGE-Device selbst:</b></p>
|
||||
<ul>
|
||||
<li><p>IODev<br/>
|
||||
Dieses Attribut ist obligatorisch und muss den Namen einer funktionierenden MQTT-Modulinstanz enthalten.
|
||||
Es werden derzeit MQTT, MQTT2_CLIENT und MQTT2_SERVER unterstuetzt.</p>
|
||||
Dieses Attribut ist obligatorisch und muss den Namen einer funktionierenden MQTT-IO-Modulinstanz enthalten.
|
||||
Es werden derzeit MQTT, MQTT2_CLIENT und MQTT2_SERVER unterstützt.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
@ -3441,14 +3450,17 @@ sub onmessage($$$) {
|
||||
|
||||
<li>
|
||||
<p>globalDefaults<br/>
|
||||
Definiert Defaults. Diese greifen in dem Fall, wenn in dem jeweiligen Geraet definierte Werte nicht zutreffen.
|
||||
s.a. <a href="#MQTT_GENERIC_BRIDGEmqttDefaults">mqttDefaults</a>.
|
||||
Definiert Defaults. Diese greifen in dem Fall, wenn in dem jeweiligen Gerät definierte Werte nicht zutreffen.
|
||||
s.a. <a href="#MQTT_GENERIC_BRIDGEmqttDefaults">mqttDefaults</a>.
|
||||
<p>Beispiel:<br>
|
||||
<code>attr <dev> sub:base={"FHEM/set/$device"} pub:base={"FHEM/$device"}</code>
|
||||
</p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>globalAlias<br/>
|
||||
Definiert Alias. Diese greifen in dem Fall, wenn in dem jeweiligen Geraet definierte Werte nicht zutreffen.
|
||||
Definiert Alias. Diese greifen in dem Fall, wenn in dem jeweiligen Gerät definierte Werte nicht zutreffen.
|
||||
s.a. <a href="#MQTT_GENERIC_BRIDGEmqttAlias">mqttAlias</a>.
|
||||
</p>
|
||||
</li>
|
||||
@ -3459,20 +3471,16 @@ sub onmessage($$$) {
|
||||
definierte Werte nicht greifen oder nicht vorhanden sind.
|
||||
s.a. <a href="#MQTT_GENERIC_BRIDGEmqttPublish">mqttPublish</a>.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>globalSubscribe ! TODO - wird derzeit nicht unterstuetzt und wird moeglicherweise gar nicht implementiert !<br/>
|
||||
Definiert Topics/Flags fuer die Aufnahme der Werte aus der MQTT-Uebertragung. Sie greifen, falls in dem jeweiligen Geraet
|
||||
definierte Werte nicht greifen oder nicht vorhanden sind. s.a. <a href="#MQTT_GENERIC_BRIDGEmqttSubscribe">mqttSubscribe</a>.
|
||||
</p>
|
||||
<p>Hinweis:<br>
|
||||
Dieses Attribut sollte nur gesetzt werden, wenn wirklich alle Werte aus den überwachten Geräten versendet werden sollen; dies wird eher nur im Ausnahmefall zutreffen!
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>globalTypeExclude<br/>
|
||||
Definiert (Geraete-)Typen und Readings, die nicht bei der Uebertragung beruecksichtigt werden.
|
||||
Werte koennen getrennt fuer jede Richtung (publish oder subscribe) vorangestellte Prefixe 'pub:' und 'sub:' angegeben werden.
|
||||
Ein einzelner Wert bedeutet, dass ein Geraet diesen Types komplett ignoriert wird (also fuer alle seine Readings und beide Richtungen).
|
||||
Definiert (Geräte-)Typen und Readings, die nicht bei der Übertragung berücksichtigt werden.
|
||||
Werte können getrennt für jede Richtung (publish oder subscribe) vorangestellte Prefixe 'pub:' und 'sub:' angegeben werden.
|
||||
Ein einzelner Wert bedeutet, dass ein Gerät diesen Types komplett ignoriert wird (also für alle seine Readings und beide Richtungen).
|
||||
Durch einen Doppelpunkt getrennte Paare werden als [sub:|pub:]Type:Reading interpretiert.
|
||||
Das bedeutet, dass an dem gegebenen Type die genannte Reading nicht uebertragen wird.
|
||||
Ein Stern anstatt Type oder auch Reading bedeutet, dass alle Readings eines Geretaetyps
|
||||
@ -3484,7 +3492,7 @@ sub onmessage($$$) {
|
||||
<li>
|
||||
<p>globalDeviceExclude<br/>
|
||||
Definiert Geraetenamen und Readings, die nicht uebertragen werden.
|
||||
Werte koennen getrennt fuer jede Richtung (publish oder subscribe) vorangestellte Prefixe 'pub:' und 'sub:' angegeben werden.
|
||||
Werte können getrennt fuer jede Richtung (publish oder subscribe) vorangestellte Prefixe 'pub:' und 'sub:' angegeben werden.
|
||||
Ein einzelner Wert bedeutet, dass ein Geraet mit diesem Namen komplett ignoriert wird (also fuer alle seine Readings und beide Richtungen).
|
||||
Durch ein Doppelpunkt getrennte Paare werden als [sub:|pub:]Device:Reading interptretiert.
|
||||
Das bedeutet, dass an dem gegebenen Geraet die genannte Readings nicht uebertragen wird.</p>
|
||||
@ -3492,90 +3500,100 @@ sub onmessage($$$) {
|
||||
<code>attr <dev> globalDeviceExclude Test Bridge:transmission-state</code></p>
|
||||
</li>
|
||||
|
||||
<p>Fuer die ueberwachten Geraete wird eine Liste der moeglichen Attribute automatisch um mehrere weitere Eintraege ergaenzt.
|
||||
Sie fangen alle mit vorher mit dem in der Bridge definiertem Prefix an. Ueber diese Attribute wird die eigentliche MQTT-Anbindung konfiguriert.<br/>
|
||||
Als Standardwert werden folgende Attributnamen verwendet: mqttDefaults, mqttAlias, mqttPublish, mqttSubscribe.
|
||||
<br/>Die Bedeutung dieser Attribute wird im Folgenden erklaert.
|
||||
</p>
|
||||
<li>
|
||||
<p>forceNEXT<br/>
|
||||
Nur relevant, wenn MQTT2_CLIENT oder MQTT2_SERVER als IODev verwendet werden. Wird dieses Attribut auf 1 gesetzt, gibt MQTT_GENERIC_BRIDGE alle eingehenden Nachrichten an weitere Client Module (z.b. MQTT2_DEVICE) weiter, selbst wenn der betreffende Topic von einem von der MQTT_GENERIC_BRIDGE überwachten Gerät verwendet wird. Im Regelfall ist dies nicht erwünscht und daher ausgeschaltet, um unnötige <i>autocreates</i> oder Events an MQTT2_DEVICEs zu vermeiden. Siehe dazu auch das <a href="#MQTT2_CLIENTclientOrder">clientOrder Attribut</a> bei MQTT2_CLIENT bzw -SERVER; wird das Attribut in einer Instance von MQTT_GENERIC _BRIDGE gesetzt, kann das Auswirkungen auf weitere Instanzen haben.</p>
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<li>
|
||||
<li><p><b>Für die überwachten Geräte</b> wird eine Liste der möglichen Attribute automatisch um mehrere weitere Einträge ergänzt. <br>
|
||||
Sie fangen alle mit vorher mit dem in der Bridge definierten <a href="#MQTT_GENERIC_BRIDGEdefine">Prefix</a> an. <b>Über diese Attribute wird die eigentliche MQTT-Anbindung konfiguriert.</b><br>
|
||||
Als Standardwert werden folgende Attributnamen verwendet: <i>mqttDefaults</i>, <i>mqttAlias</i>, <i>mqttPublish</i>, <i>mqttSubscribe</i>.
|
||||
<br/>Die Bedeutung dieser Attribute wird im Folgenden erklärt.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttDefaults">mqttDefaults</a><br/>
|
||||
Hier wird eine Liste der "key=value"-Paare erwartet. Folgende Keys sind dabei moeglich:
|
||||
Hier wird eine Liste der "key=value"-Paare erwartet. Folgende Keys sind dabei möglich:
|
||||
<ul>
|
||||
<li>'qos' <br/>definiert ein Defaultwert fuer MQTT-Paramter 'Quality of Service'.</li>
|
||||
<li>'retain' <br/>erlaubt MQTT-Nachrichten als 'retained messages' zu markieren.</li>
|
||||
<li>'base' <br/>wird als Variable ($base) bei der Konfiguration von konkreten Topics zur Verfuegung gestellt.
|
||||
<li>'base' <br/>wird als Variable ($base) bei der Konfiguration von konkreten Topics zur Verfügung gestellt.
|
||||
Sie kann entweder Text oder eine Perl-Expression enthalten.
|
||||
Perl-Expression muss in geschweifte Klammern eingeschlossen werden.
|
||||
In einer Expression koennen folgende Variablen verwendet werden:
|
||||
In einer Expression können folgende Variablen verwendet werden:
|
||||
$base = entsprechende Definition aus dem '<a href="#MQTT_GENERIC_BRIDGEglobalDefaults">globalDefaults</a>',
|
||||
$reading = Original-Readingname,
|
||||
$device = Devicename und $name = Readingalias (s. <a href="#MQTT_GENERIC_BRIDGEmqttAlias">mqttAlias</a>.
|
||||
Ist kein Alias definiert, ist $name=$reading).<br/>
|
||||
Weiterhin koennen frei benannte Variablen definiert werden, die neben den oben genannten in den public/subscribe Definitionen
|
||||
verwendet werden koennen. Allerdings ist zu beachten, dass diese Variablen dort immer mit Anfuehrungszeichen zu verwenden sind.
|
||||
Weiterhin können frei benannte Variablen definiert werden, die neben den oben genannten in den public/subscribe Definitionen
|
||||
verwendet werden können. Allerdings ist zu beachten, dass diese Variablen dort immer mit Anführungszeichen zu verwenden sind.
|
||||
</li>
|
||||
</ul>
|
||||
<br/>
|
||||
Alle diese Werte koennen durch vorangestelle Prefixe ('pub:' oder 'sub') in ihrer Gueltigkeit
|
||||
Alle diese Werte können durch vorangestelle Prefixe ('pub:' oder 'sub') in ihrer Gültigkeit
|
||||
auf nur Senden bzw. nur Empfangen begrenzt werden (soweit sinnvoll).
|
||||
Werte fuer 'qos' und 'retain' werden nur verwendet,
|
||||
wenn keine explizite Angaben darueber fuer ein konkretes Topic gemacht worden sind.</p>
|
||||
wenn keine explizite Angaben darueber für ein konkretes Topic gemacht worden sind.</p>
|
||||
<p>Beispiel:<br/>
|
||||
<code>attr <dev> mqttDefaults base={"/TEST/$device"} pub:qos=0 sub:qos=2 retain=0</code></p>
|
||||
<code>attr <dev> mqttDefaults base={"TEST/$device"} pub:qos=0 sub:qos=2 retain=0</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttAlias">mqttAlias</a><br/>
|
||||
Dieses Attribut ermoeglicht Readings unter einem anderen Namen auf MQTT-Topic zu mappen.
|
||||
Dieses Attribut ermöglicht Readings unter einem anderen Namen auf MQTT-Topic zu mappen.
|
||||
Eigentlich nur sinnvoll, wenn Topicdefinitionen Perl-Expressions mit entsprechenden Variablen sind.
|
||||
Auch hier werden 'pub:' und 'sub:' Prefixe unterstuetzt (fuer 'subscribe' gilt das Mapping quasi umgekehrt).
|
||||
Auch hier werden 'pub:' und 'sub:' Prefixe unterstützt (für 'subscribe' gilt das Mapping quasi umgekehrt).
|
||||
<br/><!--TODO: -->Alias fuer subscribe ist derzeit nicht implementiert!</p>
|
||||
<p>Beispiel:<br/>
|
||||
<code>attr <dev> mqttAlias pub:temperature=temp</code></p>
|
||||
<code>attr <dev> mqttAlias pub:temperature=temp</code></p>br>
|
||||
<i>temperature</i> ist dabei der Name des Readings in FHEM.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttPublish">mqttPublish</a><br/>
|
||||
Hier werden konkrete Topics definiert und den Readings zugeordnet (Format: <reading>:topic=<topic>).
|
||||
Weiterhin koennen diese einzeln mit 'qos'- und 'retain'-Flags versehen werden. <br/>
|
||||
Topics koennen auch als Perl-Expression mit Variablen definiert werden ($reading, $device, $name, $base).<br/>
|
||||
Weiterhin können diese einzeln mit 'qos'- und 'retain'-Flags versehen werden. <br/>
|
||||
Topics können auch als Perl-Expression mit Variablen definiert werden ($device, $reading, $name, $base sowie ggf. über <a href="#MQTT_GENERIC_BRIDGEmqttDefaults">mqttDefaults</a> weitere).<br/><br/>
|
||||
'topic' kann auch als 'readings-topic' geschrieben werden.<br/>
|
||||
Werte fuer mehrere Readings koennen auch gemeinsam gleichzeitig definiert werden,
|
||||
Werte für mehrere Readings können auch gemeinsam gleichzeitig definiert werden,
|
||||
indem sie, mittels '|' getrennt, zusammen angegeben werden.<br/>
|
||||
Wird anstatt eines Readingsnamen ein '*' verwendet, gilt diese Definition fuer alle Readings,
|
||||
fuer die keine explizite Angaben gemacht wurden.<br/>
|
||||
Ebenso koennen auch Attributwerte gesendet werden ('atopic' oder 'attr-topic').<br/>
|
||||
Sollten fuer ein Event mehrere Nachrichten (sinnvollerweise an verschiedene Topics) versendet werden, muessen jeweilige Definitionen durch Anhaengen von
|
||||
einmaligen Suffixen (getrennt von dem Readingnamen durch ein !-Zeichen) unterschieden werden: reading!1:topic=... reading!2:topic=....<br/>
|
||||
Weiterhin koennen auch Expressions (reading:expression=...) definiert werden. <br/>
|
||||
Die Expressions koennen sinnvollerweise entweder Variablen ($value, $topic, $qos, $retain, $message, $uid) veraendern, oder einen Wert != undef zurrueckgeben.<br/>
|
||||
Der Rueckhgabe wert wird als neue Nachricht-Value verwendet, die Aenderung der Variablen hat dabei jedoch Vorrang.<br/>
|
||||
Ist der Rueckgabewert undef, dann wird das Setzen/Ausfuehren unterbunden. <br/>
|
||||
Ist die Rueckgabe ein Hash (nur 'topic'), werden seine Schluesselwerte als Topic verwendet,
|
||||
Wird anstatt eines Readingsnamen ein '*' verwendet, gilt diese Definition für alle Readings,
|
||||
für die keine explizite Angaben gemacht wurden.<br/>
|
||||
für die keine expliziten Angaben gemacht wurden.<br/>
|
||||
Neben Readings können auch Attributwerte gesendet werden ('atopic' oder 'attr-topic').<br/>
|
||||
Sollten für ein Event mehrere Nachrichten (sinnvollerweise an verschiedene Topics) versendet werden, müssen jeweilige Definitionen durch Anhängen von
|
||||
einmaligen Suffixen (getrennt von dem Readingnamen durch ein !-Zeichen) unterschieden werden: reading!1:topic=... reading!2:topic=....<br/>
|
||||
Weiterhin können auch Expressions (reading:expression=...) definiert werden. <br/>
|
||||
Die Expressions können sinnvollerweise entweder Variablen ($value, $topic, $qos, $retain, $message, $uid) veraendern, oder einen Wert != undef zurrückgeben.<br/>
|
||||
Der Rückgabewert wird als neuer Nachrichten-Value verwendet, die Änderung der Variablen hat dabei jedoch Vorrang.<br/>
|
||||
Ist der Rückgabewert undef, dann wird das Setzen/Ausführen unterbunden. <br/>
|
||||
Ist die Rückgabe ein Hash (nur 'topic'), werden seine Schlüsselwerte als Topic verwendet,
|
||||
die Inhalte der Nachrichten sind entsprechend die Werte aus dem Hash.</p>
|
||||
<p>Option 'resendOnConnect' erlaubt eine Speicherung der Nachrichten,
|
||||
wenn keine Verbindung zu dem MQTT-Server besteht.
|
||||
Die zu sendende Nachrichten werden in einer Warteschlange gespeichert.
|
||||
Wird die Verbindung aufgebaut, werden die Nachrichten in der ursprungichen Reihenfolge verschickt.
|
||||
<ul>Moegliche Werte:
|
||||
Wird die Verbindung aufgebaut, werden die Nachrichten in der ursprüngichen Reihenfolge verschickt.
|
||||
<ul>Mögliche Werte:
|
||||
<li>none<br/>alle verwerfen</li>
|
||||
<li>last<br/>immer nur die letzte Nachricht speichern</li>
|
||||
<li>first<br/>immer nur die erste Nachricht speichern, danach folgende verwerfen</li>
|
||||
<li>all<br/>alle speichern, allerdings existiert eine Obergrenze von 100,
|
||||
wird es mehr, werden aelteste ueberzaelige Nachrichten verworfen.</li>
|
||||
wird es mehr, werden älteste ueberzälige Nachrichten verworfen.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>Beispiele:<br/>
|
||||
<code> attr <dev> mqttPublish temperature:topic={"$base/$name"} temperature:qos=1 temperature:retain=0 *:topic={"$base/$name"} humidity:topic=/TEST/Feuchte<br/>
|
||||
<code> attr <dev> mqttPublish temperature:topic={"$base/$name"} temperature:qos=1 temperature:retain=0 *:topic={"$base/$name"} humidity:topic=TEST/Feuchte<br/>
|
||||
attr <dev> mqttPublish temperature|humidity:topic={"$base/$name"} temperature|humidity:qos=1 temperature|humidity:retain=0<br/>
|
||||
attr <dev> mqttPublish *:topic={"$base/$name"} *:qos=2 *:retain=0<br/>
|
||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"message: $value"}<br/>
|
||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={$value="message: $value"}<br/>
|
||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"/TEST/Topic1"=>"$message", "/TEST/Topic2"=>"message: $message"}</br>
|
||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"TEST/Topic1"=>"$message", "TEST/Topic2"=>"message: $message"}</br>
|
||||
attr <dev> mqttPublish [...] *:resendOnConnect=last<br/>
|
||||
attr <dev> mqttPublish temperature:topic={"$base/temperature/01/value"} temperature!json:topic={"$base/temperature/01/json"}
|
||||
temperature!json:expression={toJSON({value=>$value,type=>"temperature",unit=>"°C",format=>"00.0"})}<br/>
|
||||
@ -3586,68 +3604,70 @@ sub onmessage($$$) {
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttSubscribe">mqttSubscribe</a><br/>
|
||||
Dieses Attribut konfiguriert das Empfangen der MQTT-Nachrichten und die entsprechenden Reaktionen darauf.<br/>
|
||||
Die Konfiguration ist aehnlich der fuer das 'mqttPublish'-Attribut. Es koennen Topics fuer das Setzen von Readings ('topic' oder auch 'readings-topic') und
|
||||
Aufrufe von 'set'-Befehl an dem Geraet ('stopic' oder 'set-topic') definiert werden. <br/>
|
||||
Ebenso koennen auch Attribute gesetzt werden ('atopic' oder 'attr-topic').</br>
|
||||
Mit Hilfe von zusaetzlichen auszufuehrenden Perl-Expressions ('expression') kann das Ergebnis vor dem Setzen/Ausfueren noch beeinflusst werden.<br/>
|
||||
In der Expression sind die folgenden Variablen verfuegbar: $device, $reading, $message (initial gleich $value).
|
||||
Die Expression kann dabei entweder die Variable $value veraendern, oder einen Wert != undef zurueckgeben. Redefinition der Variable hat Vorrang.
|
||||
Ist der Rueckgabewert undef, dann wird das Setzen/Ausfuehren unterbunden (es sei denn, $value hat einen neuen Wert). <br/>
|
||||
Ist die Rueckgabe ein Hash (nur fuer 'topic' und 'stopic'), dann werden seine Schluesselwerte als Readingsnamen bzw. 'set'-Parameter verwendet,
|
||||
Die Konfiguration ist ähnlich der für das 'mqttPublish'-Attribut. Es können Topics für das Setzen von Readings ('topic' oder auch 'readings-topic') und
|
||||
Aufrufe von 'set'-Befehl an dem Gerät ('stopic' oder 'set-topic') definiert werden. <br/>
|
||||
Attribute können ebenfalls gesetzt werden ('atopic' oder 'attr-topic').</br>
|
||||
Mit Hilfe von zusätzlichen auszuführenden Perl-Expressions ('expression') kann das Ergebnis vor dem Setzen/Ausführen noch beeinflußt werden.<br/>
|
||||
In der Expression sind die folgenden Variablen verfügbar: $device, $reading, $message (initial gleich $value).
|
||||
Die Expression kann dabei entweder die Variable $value verändern, oder einen Wert != undef zurückgeben. Redefinition der Variable hat Vorrang.
|
||||
Ist der Rückgabewert <i>undef</i>, dann wird das Setzen/Ausführen unterbunden (es sei denn, $value hat einen neuen Wert). <br/>
|
||||
Ist die Rückgabe ein Hash (nur fuer 'topic' und 'stopic'), dann werden seine Schlüsselwerte als Readingsnamen bzw. 'set'-Parameter verwendet,
|
||||
die zu setzenden Werte sind entsprechend den Werten aus dem Hash.<br/>
|
||||
Weiterhin kann das Attribut 'qos' angegeben werden ('retain' macht dagegen keinen Sinn).<br/>
|
||||
In der Topic-Definition koennen MQTT-Wildcards (+ und #) verwendet werden. <br/>
|
||||
In der Topic-Definition können MQTT-Wildcards (+ und #) verwendet werden. <br/>
|
||||
Falls der Reading-Name mit einem '*'-Zeichen am Anfang definiert wird, gilt dieser als 'Platzhalter'.
|
||||
Mehrere Definitionen mit '*' sollten somit z.B. in folgender Form verwendet werden: *1:topic=... *2:topic=...
|
||||
Der tatsaechliche Name des Readings (und ggf. des Geraetes) wird dabei durch Variablen aus dem Topic
|
||||
definiert ($device (nur fuer globale Definition in der Bridge), $reading, $name).
|
||||
Im Topic wirken diese Variablen als Wildcards, nur sinnvoll wenn Reading-Name auch nicht fest definiert ist
|
||||
(also faengt mit '*' an, oder mehrere Namen durch '|' getrennt definiert werden). <br/>
|
||||
Die Variable $name wird im Unterschied zu $reading ggf. ueber die in 'mqttAlias' definierten Aliase beeinflusst.
|
||||
definiert ($device (nur für globale Definition in der Bridge), $reading, $name).
|
||||
Im Topic wirken diese Variablen als Wildcards, was evtl. dann sinnvoll ist, wenn der Reading-Name nicht fest definiert ist
|
||||
(also mit '*' anfängt, oder mehrere Namen durch '|' getrennt definiert werden). <br/>
|
||||
Die Variable $name wird im Unterschied zu $reading ggf. über die in 'mqttAlias' definierten Aliase beeinflusst.
|
||||
Auch Verwendung von $base ist erlaubt.<br/>
|
||||
Bei Verwendung von 'stopic' wird das 'set'-Befehl als 'set <dev> <reading> <value>' ausgefuehrt.
|
||||
Fuer 'set <dev> <value>' soll als Reading-Name 'state' verwendet werden.</p>
|
||||
<p>Die oft angefragte JSON-Unterstützung kann einfach mit Hilfe von 'expression' realisiert werden.
|
||||
Dafür eignet sich eine in fhem.pl bereits vorhandene Methode: json2nameValue. Als Parameter soll $message verwendet werden.</p>
|
||||
<p>Beispiele:<br/>
|
||||
<code>attr <dev> mqttSubscribe temperature:topic=/TEST/temperature test:qos=0 *:topic={"/TEST/$reading/value"} <br/>
|
||||
attr <dev> mqttSubscribe desired-temperature:stopic={"/TEST/temperature/set"}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"/TEST/light/set"} state:expression={...}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"/TEST/light/set"} state:expression={$value="x"}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"/TEST/light/set"} state:expression={"R1"=>$value, "R2"=>"Val: $value", "R3"=>"x"}
|
||||
attr <dev> mqttSubscribe verbose:atopic={"/TEST/light/verbose"}
|
||||
attr <dev> mqttSubscribe json:topic=/XTEST/json json:expression={json2nameValue($message)}
|
||||
</code></p>
|
||||
Bei Verwendung von 'stopic' wird der 'set'-Befehl als 'set <dev> <reading> <value>' ausgefuehrt.
|
||||
Um den set-Befehl direkt am Device ohne Angabe eines Readingnamens auszuführen (also 'set <dev> <value>') muss als Reading-Name 'state' verwendet werden.</p>
|
||||
<p>Um Nachrichten im JSON-Format zu empfangen, kann mit Hilfe von 'expression' direkt die in fhem.pl bereitgestellte Funktion <i>json2nameValue</i> aufgerufen werden, als Parameter ist <i>$message</i> anzugeben.</p>
|
||||
<br>
|
||||
<p>Einige Beispiele:<br/>
|
||||
<code>attr <dev> mqttSubscribe temperature:topic=TEST/temperature test:qos=0 *:topic={"TEST/$reading/value"} <br/>
|
||||
attr <dev> mqttSubscribe desired-temperature:stopic={"TEST/temperature/set"}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"TEST/light/set"} state:expression={...}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"TEST/light/set"} state:expression={$value="x"}<br/>
|
||||
attr <dev> mqttSubscribe state:stopic={"TEST/light/set"} state:expression={"R1"=>$value, "R2"=>"Val: $value", "R3"=>"x"}
|
||||
attr <dev> mqttSubscribe verbose:atopic={"TEST/light/verbose"}
|
||||
attr <dev> mqttSubscribe json:topic=XTEST/json json:expression={json2nameValue($message)}
|
||||
</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttForward">mqttForward</a><br/>
|
||||
Dieses Attribut definiert was passiert, wenn eine und dasselbe Reading sowohl aboniert als auch gepublisht wird.
|
||||
Moegliche Werte: 'all' und 'none'. <br/>
|
||||
Mögliche Werte: 'all' und 'none'. <br/>
|
||||
Bei 'none' werden per MQTT angekommene Nachrichten nicht aus dem selben Gerät per MQTT weiter gesendet.<br/>
|
||||
Die Einstellung 'all' bewirkt das Gegenteil, also damit wird das Weiterleiten ermoeglicht.<br/>
|
||||
Fehlt dieser Attribut, dann wird standartmaeßig für alle Geraetetypen außer 'Dummy' die Einstellung 'all' angenommen
|
||||
(damit koennen Aktoren Befehle empfangen und ihre Änderungen im gleichem Zug weiter senden)
|
||||
und fuer Dummies wird 'none' verwendet. Das wurde so gewaehlt, weil Dummies oft als eine Art GUI-Schalterelement verwendet werden.
|
||||
In diesem Fall wuerde 'all' unter Umstaenden eine Endlosschleife der Nachrichten verursachen.
|
||||
Die Einstellung 'all' bewirkt das Gegenteil, also damit wird das Weiterleiten ermöglicht.<br/>
|
||||
Fehlt dieser Attribut, dann wird standardmäßig für alle Gerätetypen außer 'Dummy' die Einstellung 'all' angenommen
|
||||
(damit können Aktoren Befehle empfangen und ihre Änderungen im gleichem Zug weiter senden)
|
||||
und für Dummies wird 'none' verwendet. Das wurde so gewählt, da dummy von vielen Usern als eine Art GUI-Schalterelement verwendet werden.
|
||||
'none' verhindert hier unter Umständen das Entstehen einer Endlosschleife der Nachrichten.
|
||||
|
||||
</p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p><a name="MQTT_GENERIC_BRIDGEmqttDisable">mqttDisable</a><br/>
|
||||
Wird dieses Attribut in einem Geraet gesetzt, wird dieses Geraet vom Versand bzw. Empfang der Readingswerten ausgeschlossen.</p>
|
||||
Wird dieses Attribut in einem Gerät gesetzt, wird dieses Gerät vom Versand bzw. Empfang der Readingswerten ausgeschlossen.</p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Beispiele</b></p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Bridge fuer alle moeglichen Geraete mit dem Standardprefix:<br/>
|
||||
<p>Bridge für alle möglichen Geräte mit dem Standardprefix:<br/>
|
||||
<code>defmod mqttGeneric MQTT_GENERIC_BRIDGE<br/>
|
||||
attr mqttGeneric IODev mqtt</code>
|
||||
</p>
|
||||
@ -3655,14 +3675,14 @@ sub onmessage($$$) {
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Bridge mit dem Prefix 'mqtt' fuer drei bestimmte Geraete:<br/>
|
||||
<code> defmod mqttGeneric MQTT_GENERIC_BRIDGE mqtt sensor1,sensor2,sensor3<br/>
|
||||
<p>Bridge mit dem Prefix 'mqttSensors' fuer drei bestimmte Geräte:<br/>
|
||||
<code> defmod mqttGeneric MQTT_GENERIC_BRIDGE mqttSensors sensor1,sensor2,sensor3<br/>
|
||||
attr mqttGeneric IODev mqtt</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Bridge fuer alle Geraete in einem bestimmten Raum:<br/>
|
||||
<p>Bridge für alle Geräte in einem bestimmten Raum:<br/>
|
||||
<code>defmod mqttGeneric MQTT_GENERIC_BRIDGE mqtt room=Wohnzimmer<br/>
|
||||
attr mqttGeneric IODev mqtt</code></p>
|
||||
</p>
|
||||
@ -3671,14 +3691,14 @@ sub onmessage($$$) {
|
||||
<li>
|
||||
<p>Einfachste Konfiguration eines Temperatursensors:<br/>
|
||||
<code>defmod sensor XXX<br/>
|
||||
attr sensor mqttPublish temperature:topic=/haus/sensor/temperature</code></p>
|
||||
attr sensor mqttPublish temperature:topic=haus/sensor/temperature</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Alle Readings eines Sensors (mit ihren Namen wie sie sind) per MQTT versenden:<br/>
|
||||
<p>Alle Readings eines Sensors (die Namen werden unverändet übergeben) per MQTT versenden:<br/>
|
||||
<code> defmod sensor XXX<br/>
|
||||
attr sensor mqttPublish *:topic={"/sensor/$reading"}</code></p>
|
||||
attr sensor mqttPublish *:topic={"sensor/$reading"}</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
@ -3691,7 +3711,7 @@ sub onmessage($$$) {
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Topic-Definition nur fuer bestimmte Readings mit deren gleichzeitigen Umbennenung (Alias):<br/>
|
||||
<p>Topic-Definition nur für bestimmte Readings mit deren gleichzeitigen Umbennenung (Alias):<br/>
|
||||
<code>defmod sensor XXX<br/>
|
||||
attr sensor mqttAlias temperature=temp humidity=hum<br/>
|
||||
attr sensor mqttDefaults base={"/$device/$name"}<br/>
|
||||
@ -3700,31 +3720,31 @@ sub onmessage($$$) {
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Beispiel fuer eine zentrale Konfiguration in der Bridge fuer alle Devices, die Reading 'temperature' besitzen:<br/>
|
||||
<p>Beispiel für eine zentrale Konfiguration in der Bridge für alle Devices, die Reading 'temperature' besitzen:<br/>
|
||||
<code>defmod mqttGeneric MQTT_GENERIC_BRIDGE <br/>
|
||||
attr mqttGeneric IODev mqtt <br/>
|
||||
attr mqttGeneric defaults sub:qos=2 pub:qos=0 retain=0 <br/>
|
||||
attr mqttGeneric publish temperature:topic={"/haus/$device/$reading"} <br/>
|
||||
attr mqttGeneric publish temperature:topic={"haus/$device/$reading"} <br/>
|
||||
</code></p>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Beispiel fuer eine zentrale Konfiguration in der Bridge fuer alle Devices <br/>
|
||||
(wegen einer schlechten Uebersicht und einer unnoetig grossen Menge eher nicht zu empfehlen):<br/>
|
||||
<p>Beispiel für eine zentrale Konfiguration in der Bridge für alle Devices <br/>
|
||||
(wegen einer schlechten Übersicht und einer unnötig grossen Menge eher nicht zu empfehlen!):<br/>
|
||||
<code>defmod mqttGeneric MQTT_GENERIC_BRIDGE <br/>
|
||||
attr mqttGeneric IODev mqtt <br/>
|
||||
attr mqttGeneric defaults sub:qos=2 pub:qos=0 retain=0 <br/>
|
||||
attr mqttGeneric publish *:topic={"/haus/$device/$reading"} <br/></code></p>
|
||||
attr mqttGeneric publish *:topic={"haus/$device/$reading"} <br/></code></p>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Einschraenkungen:</b></p>
|
||||
<p><b>Einschränkungen:</b></p>
|
||||
|
||||
<ul>
|
||||
<li>Wenn mehrere Readings das selbe Topic abonnieren, sind dabei keine unterschiedlichen QOS moeglich.</li>
|
||||
<li>Wird in so einem Fall QOS ungleich 0 benoetigt, sollte dieser entweder fuer alle Readings gleich einzeln definiert werden,
|
||||
<li>Wenn mehrere Readings das selbe Topic abonnieren, sind dabei keine unterschiedlichen QOS möglich.</li>
|
||||
<li>Wird in so einem Fall QOS ungleich 0 benötigt, sollte dieser entweder fuer alle Readings gleich einzeln definiert werden,
|
||||
oder allgemeingueltig ueber Defaults. <br/>
|
||||
Ansonsten wird beim Erstellen von Abonnements der erst gefundene Wert verwendet. </li>
|
||||
<li>Abonnements werden nur erneuert, wenn sich das Topic aendert; QOS-Flag-Aenderung alleine wirkt sich daher erst nach einem Neustart aus.</li>
|
||||
@ -3742,7 +3762,6 @@ sub onmessage($$$) {
|
||||
<li>templates (template in der Bridge, mqttUseTemplate in Device)</li>
|
||||
</ul>
|
||||
-->
|
||||
</ul>
|
||||
|
||||
=end html_DE
|
||||
=cut
|
||||
|
Loading…
Reference in New Issue
Block a user