# MQTT

> Geräte, die über einen externen MQTT-Broker veröffentlichen, in einfachem MQTT oder Sparkplug B, mit dem Broker als dem Knoten, den sich alle Geräte darunter teilen, und die eigenen Daten der Station, auf einem Broker veröffentlicht.

Der Treiber MQTT liest und schreibt die Tags von Anlagen, die über einen **externen MQTT-Broker** veröffentlichen: ein Gateway, ein Funksensor, ein Node-RED-Flow, ein Edge-Node, der Sparkplug B spricht. Die Station ist Client dieses Brokers: Sie abonniert die Topics, die ihre Tags lesen, und veröffentlicht die Schreibvorgänge, die Sie auslösen, und jeder Broker kann die eigenen Daten der Station veröffentlichen, die Tags, Logic-Variablen und Alarme, die auf seiner [Karte Veröffentlichen](#the-publish-card) stehen, als JSON oder in Sparkplug B. Sie ist Client und kein Broker; Anlage und Station verbinden sich also beide mit einem Broker. Haben Sie keinen, kann der eigene [MQTT-Broker](connector-mqtt-broker) der Station dieser Broker sein, und sein Einschalten fügt diesem Treiber den Broker **Diese Station** hinzu. [Einen Broker installieren](#installing-a-broker) zeigt, wie Sie einen separaten einrichten.

Alle Geräte hinter einem Broker nutzen dieselbe Verbindung, deshalb ist die Topologie
**Treiber → Broker → Gerät → Tag**: Der **Broker** besitzt, wo er antwortet und wie sich die
Station bei ihm anmeldet, einmal eingetragen; jedes **Gerät** darunter besitzt nur die Art,
wie es veröffentlicht, **Einfaches MQTT** oder **Sparkplug B**, und seine Tags. Beide
Protokolle stehen unter einem Broker nebeneinander. Werte kommen per Abonnement, nicht per
Abfrage, daher hat kein MQTT-Gerät und kein MQTT-Tag ein Abfrageintervall.

## Die Seite des Treibers {#the-drivers-page}

Die Seite des Treibers MQTT listet Broker statt Geräte. Der Satz unter ihrer Kopfzeile lautet
"Jeder Broker ist eine Verbindung zu einem externen MQTT-Broker. Richten Sie ein, wo er antwortet und wie sich die Station anmeldet, und fügen Sie dann die Geräte hinzu, die über ihn veröffentlichen."
Die Tabelle **MQTT-Broker** trägt **Broker hinzufügen** rechts von ihrem Titel und eine Zeile
pro Broker: **Bezeichnung**, **Adresse** (`mqtt://host:port`, oder `mqtts://host:port` über
TLS, leer, solange der Broker keinen Host hat), **Geräte**, **Zustand** (ein Punkt und der
Zustand des Brokers mit dem, was seine Geräte tun, etwa "Verbunden · 2/2 Geräte verbunden"),
dann **Öffnen** und, für Connector konfigurieren, **Aktivieren**, **Deaktivieren** und
**Löschen**. Die leere Tabelle sagt "Noch keine Broker." Ein Broker, der die Station abgewiesen hat, trägt die rote Marke des Baums hinter seinem Namen, und die Seite nennt unter ihrer Kopfzeile die Broker mit Fehler ("1 Broker mit Fehler: Plant").

Im Baum zählt die Zeile des Treibers beide Ebenen ("1 Broker · 2 Geräte"), und die Kopfzeile
der Seite zeigt die Zahl der Broker in Klammern. Im Menü Neu… der Spalte bietet der Eintrag
MQTT **Neuer Broker**, dann jeden Broker mit seinem eigenen **Neues Gerät** und seinen Geräten,
und ein Rechtsklick auf die Zeile des Treibers bietet **Broker hinzufügen**. Die Leiste des
Treibers hat keine Gerätesuche: Ein Suchlauf hört auf einem einzigen Broker zu, deshalb sitzt
er auf der Seite des Brokers. Einmal hinzugefügt, steht der Treiber im Baum unter dem Ordner
Treiber, mit oder ohne Broker.

## Der Broker {#the-broker}

**Broker hinzufügen**, **Neuer Broker** im Menü Neu… und der Rechtsklick auf die Zeile des Treibers
legen einen Broker namens "Neuer Broker" an (dann "Neuer Broker 2"), deaktiviert, damit seine
Verbindung eingetragen ist, bevor sich die Station verbindet. Das Aktionsprotokoll sagt es:
"Deaktivierten Broker 'Neuer Broker' angelegt. Tragen Sie ein, wo er antwortet, und aktivieren Sie ihn dann."
Der Broker wird nicht geöffnet: Er ist in der Tabelle MQTT-Broker auf der Seite des Treibers markiert, auf die die Ansicht aus Neu… oder dem Rechtsklick wechselt. Seine Seite, erreicht über **Öffnen** in seiner Zeile oder seine Zeile im Baum, trägt den Satz "Ein MQTT-Broker: wo er antwortet und wie sich die Station bei ihm anmeldet. Jedes Gerät darunter teilt diese Verbindung."
und in der Kopfzeile mit dem Zustand, seinem Punkt und der Adresse. Unter der Kopfzeile werden die Geräte des Brokers genannt, die einen eigenen Fehler haben ("1 Gerät mit Fehler: Pump"); solange der Broker selbst einen Fehler hat, verweisen seine Geräte auf ihn: Die Seite eines Geräts sagt "Dieses Gerät läuft über den Broker Plant, der einen Fehler hat. Die Seite des Brokers sagt, warum."

### Die Karte Verbindung zum Broker {#the-broker-connection-card}

| Feld | Bedeutung | Standard |
| --- | --- | --- |
| **Bezeichnung** | Der Anzeigename des Brokers im Baum und bei jedem Gerät darunter. Er gelangt nie in eine Adresse. Leer wird er abgelehnt: "Der Name des Brokers ist erforderlich." | "Neuer Broker" |
| **Hostadresse** | Der Hostname oder die IP-Adresse des Brokers. Eine ganze Adresse lässt sich einfügen: `mqtt://` oder `tcp://` davor stellt den Übertragungsweg auf Klartext, `mqtts://`, `ssl://` oder `tls://` auf TLS, ein Port hinter dem Host wandert in **Port**, und der Host wird bloß gespeichert. Ein anderes Schema, ein Pfad oder eine Anmeldung in der Adresse werden unter dem Feld abgelehnt, und jedes Feld behält, was es hatte: "'http://192.168.0.20' ist keine Broker-Adresse. Schreiben Sie den Hostnamen oder die IP-Adresse des Brokers, wahlweise als mqtt://host:port oder mqtts://host:port." | leer |
| **Port** | Der TCP-Port, auf dem der Broker antwortet, 1 bis 65535. | 1883 |
| **Übertragungsweg** | Das Kontrollkästchen **TLS verwenden**. Angehakt ist die Verbindung verschlüsselt, und das Zertifikat des Brokers wird gegen den Windows-Zertifikatspeicher oder gegen die unter [Anlagenzugriff](#equipment-access) freigegebenen Zertifikate geprüft: "Verschlüsselt: Windows muss dem Zertifikat des Brokers vertrauen, oder es ist unter Anlagenzugriff auf der Seite des MQTT-Treibers freigegeben." Ohne Haken warnt der Hinweis "Unverschlüsselt: Werte und Passwort werden im Klartext übertragen." Das Umschalten setzt einen auf 1883 belassenen Port auf 8883 und zurück; jeder andere Port bleibt, wie er ist. | ohne Haken |
| **Benutzername**, **Passwort** | Das Konto, mit dem sich die Station beim Broker anmeldet. Ein leerer Benutzername meldet sich anonym an. Das Passwort wird im Ruhezustand geschützt wie die Zugangsdaten eines Geräts und erscheint nie in einer Adresse, im Journal oder in der Antwort eines Agenten. | leer |
| **Client-ID** | Der Name, den die Sitzung der Station auf dem Broker trägt, 1 bis 128 Zeichen ohne Steuerzeichen. Ein Broker hält eine Sitzung pro Client-ID und wirft die ältere von zweien hinaus, deshalb gehört eine Client-ID zu genau einem Broker dieser Station: "Die Client-ID 'GanterLab01' gehört bereits zum Broker 'Plant'. Zwei Sitzungen mit derselben Client-ID werfen sich gegenseitig vom Broker: Wählen Sie eine andere." Teilen sich zwei Stationen einen Broker, behält jede ihre eigene. | `GanterLab` und 14 Hexadezimalziffern, erzeugt |
| **Keep-Alive (s)** | Wie oft die Sitzung beweist, dass sie lebt, wenn sonst nichts übertragen wird: "Das Keep-Alive muss zwischen 5 und 3600 Sekunden liegen." | 60 |

Unter den Feldern sagt ein Satz, was der Broker und seine Geräte tun, was dem Broker noch
fehlt, und "Alle Geräte unter diesem Broker und das, was die Station auf ihm veröffentlicht, teilen diese Verbindung: Die Sitzung öffnet sich, sobald das erste aktivierte Gerät oder die erste veröffentlichte Zeile sie braucht."
Alle Felder bleiben bearbeitbar, während der Broker aktiviert ist. Eine gespeicherte Änderung
daran, wo er antwortet, am Übertragungsweg, an der Anmeldung, an der Client-ID oder am
Keep-Alive verbindet die eine Sitzung neu, die sich alle Geräte unter dem Broker teilen.

### Die Befehlsleiste {#the-command-bar}

| Befehl | Wirkung | Ausgegraut, wenn (Situation) | Nicht gezeichnet, wenn (Rolle) |
| --- | --- | --- | --- |
| **Aktivieren** | Lässt die Geräte unter dem Broker seine Sitzung nutzen. Ein Broker ohne Host wird abgelehnt: "Geben Sie den Hostnamen oder die IP-Adresse des Brokers ein, bevor der Broker aktiviert wird." | Er ist schon aktiviert, die Verbindung ist nicht vollständig ("Die Verbindung dieses Brokers ist noch nicht vollständig."), ein Suchlauf läuft, oder die Station lehnt Änderungen ab. | Ohne Connector konfigurieren. |
| **Deaktivieren** | Schließt die Sitzung für jedes Gerät darunter; jedes Gerät behält seine eigene Wahl Aktiviert und kommt so zurück, wie es war, wenn der Broker wieder aktiviert wird. | Er ist schon deaktiviert, ein Suchlauf läuft, oder die Station lehnt Änderungen ab. | Ohne Connector konfigurieren. |
| **Broker löschen** (in der Gefahrenfarbe, rechts) | Fragt zuerst. Ein leerer Broker: "Dieser Broker hat keine Geräte."; einer mit Geräten: "Damit werden auch die 2 Geräte des Brokers und alle deren Tags gelöscht." Danach ist der Treiber MQTT gewählt, und das Aktionsprotokoll sagt "Broker 'Plant' und seine 2 Geräte gelöscht." | Ein Suchlauf läuft ("Ein Suchlauf benutzt diesen Broker. Warten Sie, bis er fertig ist."), oder die Station lehnt Änderungen ab. | Ohne Connector konfigurieren. |

Ein Rechtsklick auf die Zeile eines Brokers bietet **Gerät hinzufügen**, **Aktivieren**,
**Deaktivieren** und **Löschen**.

### Zustände des Brokers {#broker-states}

Der Broker meldet seine Sitzung getrennt von seinen Geräten, in der Zeile des Baums, in der
Broker-Tabelle des Treibers und in seiner eigenen Kopfzeile:

| Zustand | Punkt | Bedeutung |
| --- | --- | --- |
| **Aus** | grau | Der Broker ist deaktiviert. |
| **Keine Sitzung** | grau | Aktiviert, aber kein aktiviertes Gerät nutzt ihn, und seine Karte Veröffentlichen veröffentlicht nichts, daher wird keine Sitzung geöffnet. |
| **Verbindung wird aufgebaut…** | bernsteinfarben | Ein Gerät ist aktiviert oder der Broker veröffentlicht, und die Sitzung verbindet sich oder verbindet sich nach einem Verlust neu. |
| **Verbunden** | grün | Die Sitzung ist verbunden. |
| **Nicht erreichbar** | rot | Der Broker war nicht erreichbar oder hat die Station abgewiesen. Die Ursache steht rot unter der Kopfzeile in der Sprache der Station und, in den Worten des Treibers, als Tooltip der Fehlermarke der Zeile, in Begriffen dessen, was zu korrigieren ist: Auf dem Port antwortet nichts, der Name ist in diesem Netz unbekannt, Benutzername oder Passwort wurden abgelehnt, das Zertifikat ist nicht vertrauenswürdig oder wartet unter [Anlagenzugriff](#equipment-access) auf Freigabe, ein anderer Client hat die Sitzung mit derselben Client-ID übernommen. Ein Broker, der den Port oder einen Client ohne Benutzernamen abweist, wird stattdessen mit seiner Einstellung gesagt (siehe [Den Broker vorbereiten](#prepare-the-broker)). |

Die Zeile im Baum zeigt den Zustand und die Zahl der Geräte ("Verbunden · 2 Geräte"), und die
Zusammenfassung unter der Karte ergänzt, was die Geräte tun: "Verbunden · 2/2 Geräte verbunden",
"Verbunden · 1 verbunden · 1 mit Störungen", "Keine Sitzung · keine aktivierten Geräte". Ein
Sparkplug B-Gerät, das seinen Tod angekündigt hat, nimmt nur sich selbst vom Netz: Der Broker
bleibt verbunden. Die Sitzung spricht MQTT 5 und weicht bei einem Broker, der es nicht
spricht, auf MQTT 3.1.1 aus, beginnt sauber und verbindet sich selbst neu, wobei sie zwischen
den Versuchen immer länger wartet, solange der Broker fortbleibt.

### Die Karte Geräte suchen {#the-discover-devices-card}

Nur für Connector konfigurieren gezeichnet, unter dem Satz "Hört eine Weile auf diesem Broker mit: die Sparkplug B-Edge-Nodes und -Geräte, die sich ankündigen, und die Topics unter einem Filter."

| Feld | Bedeutung | Standard |
| --- | --- | --- |
| **Zuhören (s)** | Wie lange der Suchlauf zuhört, 3 bis 60 Sekunden. | 10 |
| **Topic-Filter** | Die einfachen Topics, die als Tags eines Geräts gelistet werden. Die Platzhalter `+` (eine Ebene) und `#` (diese Ebene und alles darunter, nur am Ende) sind erlaubt, daher "z. B. plant/#". Leer listet nur Sparkplug B-Geräte. | leer |

**Geräte suchen** startet den Suchlauf und wird zu **Abbrechen**, solange er läuft. Der Satz
unter den Feldern sagt, was er tun wird ("Hört 10 s lang auf 192.168.0.20:1883."), und die
Fortschrittszeile zählt das Fenster ("Höre auf 192.168.0.20:1883 · 4 von 10 s…"). Der Suchlauf
braucht einen am Broker gespeicherten Host: Bis dahin sagt die Karte "Geben Sie den Host des Brokers ein und lassen Sie die Änderung vor der Gerätesuche speichern."
Eine ausstehende Änderung am Broker wird zuerst gespeichert; geht das nicht, startet nichts:
"Die Gerätesuche wurde nicht gestartet, weil die Änderung am Broker nicht gespeichert werden konnte."

Was ein Suchlauf auf dem Broker tut:

- Er verbindet sich unter einer eigenen Client-ID, wirft also nie die Sitzung der Geräte vom
  Broker, und darf laufen, während der Broker aktiviert und in Gebrauch ist.
- Er abonniert alle Sparkplug B-Topics (`spBv1.0/#`) und den Topic-Filter. Sparkplug
  B-Birth-Zertifikate werden nicht gehalten, deshalb wird ein Edge-Node, der ohne eines
  gehört wird, gebeten, sich neu anzukündigen (der Befehl `Node Control/Rebirth`, die einzige
  Nachricht, die der Suchlauf veröffentlicht); ein laufender Edge-Node antwortet innerhalb
  des Fensters.
- Jeder Edge-Node und jedes Gerät dahinter, das sich ankündigt (NBIRTH, DBIRTH), wird ein
  Kandidat mit seinen Metriken als Tags, typisiert nach dem, was die Geburt deklariert. Die
  eigene Technik des Edge-Nodes (`bdSeq` und die Metriken `Node Control/…` und
  `Device Control/…`) bleibt außen vor, ebenso die Metriken, die kein Tag liest (Arrays,
  Datensätze, Templates, Eigenschaftssätze, Bytes, Dateien), nach Grund gezählt. Ein
  Edge-Node, der gehört, aber im Fenster nicht geboren wurde, wird ohne Tags angeboten.
- Mit einem Topic-Filter werden die darunter gehörten einfachen Topics ein eigener Kandidat:
  Jedes Topic ist ein Tag, oder bei JSON-Nutzdaten ist jeder Wert darin eines über seinen
  Wertpfad (bis zu 32 pro Topic, vier Ebenen tief, die ersten 8 Elemente eines Arrays). Eine
  Zahl wird als Double angeboten, `true` oder `false` als Boolean, alles andere als String.
  Die Liste endet bei 500 Topics. Ein Topic, dessen Herausgeber seine letzte Nachricht hält,
  wird sofort gehört; jedes andere nur, wenn es im Fenster veröffentlicht.
- Nichts wird gespeichert, bis Sie einen Kandidaten hinzufügen. Abbrechen beendet das Fenster
  sofort.

Die Ergebniskarte **Gefundene Geräte** listet **Veröffentlicht als** (`group/edge node`, mit
`/device` hinter einem Edge-Node, oder "Einfache Topics"), **Gerät** (der Name, unter dem es
hinzugefügt wird, bearbeitbar: die Geräte- oder Edge-Node-ID, oder die Ebenen des Filters vor
seinem ersten Platzhalter), **Ergebnis** ("12 von 12 Tags ausgewählt") und
**Gerät hinzufügen**, das das Gerät unter diesem Broker mit diesen Tags anlegt. Eine schon auf
dem Broker eingerichtete Sparkplug B-Identität zeigt "Bereits konfiguriert" und bietet
stattdessen **Öffnen**. Ein Suchlauf, der nichts gehört hat, sagt
"Während des Suchlaufs hat sich auf diesem Broker nichts angekündigt."

Ein Gerät, das Sie schon haben, findet, was es noch nicht liest, von seiner eigenen Seite aus: **Tags suchen** im Kopf seiner Karte der Tags lauscht 10 s an seinem Broker. Ein Sparkplug-B-Gerät hört nur seinen eigenen Edge Node, der um seine Geburt gebeten wird, während kein anderer Edge Node um irgendetwas gebeten wird; ein einfaches Gerät hört die Topics unter den Ebenen, die seine Tags gemeinsam haben (`plant/oven/#` für `plant/oven/temperature` und `plant/oven/count`), und jedes Topic des Brokers, wenn sie keine gemeinsam haben. Angeboten werden nur die Werte, für die es noch kein Tag hat (siehe [Die Tags eines Geräts suchen](connector-discovery#discovering-a-devices-tags)).

### Die Karte Geräte {#the-devices-card}

"Jedes Gerät liest einfache Topics oder einen Sparkplug B-Edge-Node bzw. ein Sparkplug B-Gerät. Die Verbindung wird vom Broker geerbt und lässt sich hier nicht ändern."
**Gerät hinzufügen** legt "Neues Gerät" unter diesem Broker an, aktiviert, in einfachem MQTT,
markiert in dieser Tabelle und in den sichtbaren Bereich gerollt: "Gerät 'Neues Gerät' auf 'Plant' hinzugefügt." Die Tabelle listet **Gerät**,
**Veröffentlicht als**, **Tags** und **Zustand**, mit Öffnen, Aktivieren, Deaktivieren
und Löschen in jeder Zeile; leer sagt sie "Unter diesem Broker ist kein Gerät eingerichtet." Ein Gerät mit einem eigenen Fehler trägt die rote Marke des Baums hinter seinem Namen.

### Die Karte Veröffentlichen {#the-publish-card}

Die letzte Karte veröffentlicht die eigenen Daten der Station auf diesem Broker, unter dem Satz "Die Station veröffentlicht jede Zeile auf diesem Broker als JSON unter ihrem Topic, sobald sich der Wert oder seine Qualität ändert, und alle Zeilen erneut, sobald die Verbindung aufgebaut wird. Der Broker behält die letzte Nachricht jedes Topics für alle, die es später abonnieren. Die Station abonniert nur das Schreib-Topic jeder Zeile mit Lesen und schreiben."
Wer den Connector ansehen darf, liest die Karte; wer ihn konfigurieren darf, ändert sie. Der
Broker Diese Station des eigenen [MQTT-Brokers](connector-mqtt-broker) der Station hat dieselbe Karte.

| Feld | Bedeutung | Standard |
| --- | --- | --- |
| **Veröffentlichungsformat** | Wie die Zeilen hinausgehen: als **JSON** unter dem Topic jeder Zeile ([Veröffentlichen](#publishing)) oder als **Sparkplug B**, die Station als Edge-Node des Brokers ([Veröffentlichen in Sparkplug B](#publishing-in-sparkplug-b)). Sein Tooltip: "Wie die Zeilen hinausgehen: als JSON unter dem eigenen Topic jeder Zeile oder als Sparkplug B, mit dieser Station als Edge-Node, den Ignition und andere Sparkplug B-Konsumenten von selbst finden." | JSON |
| **Topic-Präfix** | Nur bei JSON. Die Ebene, unter der das Topic jeder neuen Zeile vorgeschlagen wird. Leer zeigt das Feld den Standard und verwendet ihn. "Das Topic-Präfix darf weder + noch # enthalten, nicht mit $ beginnen und kein Zeichen enthalten, das kein Topic enthalten darf." Eine Änderung lässt die Topics, die schon in der Liste stehen, unverändert. | `ganterlab/` und der Name der Station |
| **Gruppen-ID** | Nur bei Sparkplug B, an der Stelle des Präfixes. Die Sparkplug B-Gruppe des Edge-Nodes der Station auf diesem Broker; leer ist es `GanterLab`. Eine Gruppe mit `/`, `+` oder `#` wird unter dem Feld abgelehnt, und der Broker wird erst gespeichert, wenn sie korrigiert ist. | `GanterLab` |

Bei Sparkplug B sagt der Satz unter dem Titel stattdessen "Die Station ist auf diesem Broker ein Sparkplug B-Edge-Node: Die Variablen und Alarme der Logic sind seine eigenen Metriken, und jedes Gerät mit Zeilen ist ein Sparkplug B-Gerät. Sie kündigt jede Metrik an, wenn die Verbindung öffnet und wann immer sich die Liste ändert, und veröffentlicht danach jeden Wert und jede Qualität, die sich ändern. Nur eine Zeile mit Lesen und schreiben nimmt einen Wert aus einem Befehl an.", und unter den Feldern zeigt **Edge-Node-ID (der Name der Station)** den Edge-Node, als der sie veröffentlicht.

Die Tabelle führt **Quelle**, **MQTT-Topic** und **Zugriff** auf, nach Topic geordnet; eine Zeile,
deren Quelle noch nicht gewählt ist, lautet "Noch keine Quelle". Ohne Zeilen steht dort "Noch wird nichts auf diesem Broker veröffentlicht. Fügen Sie eine Zeile mit Neue Zeile hinzu."
Bei Sparkplug B ist die Spalte **MQTT-Topic** die Spalte **Metrik**: ein Tag hinter seinem Gerät (`Oven · Temperature`), eine Variable oder ein Alarm mit seinem Namen auf dem Edge-Node (`Logic/Oven/Setpoint`, `Alarms/High`).
Ist der Broker deaktiviert und hat die Liste Zeilen, sagt ein Hinweis "Der Broker ist deaktiviert, also wird nichts veröffentlicht, bis er aktiviert wird."
Hat eine Zeile des Brokers Lesen und schreiben, sagt ein zweiter Hinweis "Zeilen mit Lesen und schreiben nehmen Werte an, die unter ihrem Schreib-Topic veröffentlicht werden. Wer auf diesem Broker veröffentlichen kann, kann diese Quellen ändern: Benutzername und Passwort des Brokers sind ihr einziger Schutz." Bei Sparkplug B sagt er "Zeilen mit Lesen und schreiben nehmen Werte aus Sparkplug B-Befehlen an (NCMD, DCMD). Wer auf diesem Broker veröffentlichen kann, kann diese Quellen ändern: Benutzername und Passwort des Brokers sind ihr einziger Schutz."

| Befehl | Wirkung | Ausgegraut, wenn (Situation) | Nicht gezeichnet, wenn (Rolle) |
| --- | --- | --- | --- |
| **Neue Zeile** | Fügt eine Zeile hinzu, die noch nichts veröffentlicht, und wählt sie: "Zeile zur Liste Veröffentlichen des Brokers hinzugefügt. Wählen Sie ihre Quelle." | Ein Lauf hält die Station, oder die Runtime ist gestoppt. | Ohne Connector konfigurieren. |
| **Zeile löschen** (Gefahrenfarbe) | Löscht die gewählte Zeile sofort; ihr Tooltip nennt, was sie veröffentlicht. Die Station veröffentlicht sie nicht mehr; die Nachricht, die der Broker unter ihrem Topic aufbewahrt, bleibt dort. | Keine Zeile ist gewählt ("Wählen Sie eine Zeile der Liste, um sie zu löschen."), ein Lauf hält die Station, oder die Runtime ist gestoppt. | Ohne Connector konfigurieren. |

Die Felder einer Zeile werden gespeichert, sobald sie sich ändern:

| Feld | Was es tut |
| --- | --- |
| **Quelle** | Was die Zeile veröffentlicht: "(keine)", dann jedes aktivierte Tag eines aktivierten Geräts ("Tag · Simulated · Oven · Temperature"), jede Logic-Variable, die einen Wert hält, und jeder Alarm, mit ihren Ordnern benannt. Ein Gerätebefehl veröffentlicht nichts und wird nicht angeboten. Die Zeile hält ihre Quelle über deren Identität, eine Umbenennung lässt die Zeile also bei ihr, und die Karte [Verwendet von](connector-tags#the-used-by-card) der Quelle führt die Zeile auf. |
| **MQTT-Topic** | Nur bei JSON. Wo die Zeile veröffentlicht. Das Wählen einer Quelle schlägt ein Topic aus ihrem Namen vor: `<prefix>/<device>/<tag>` für ein Tag, `<prefix>/logic/<folders>/<variable>` für eine Variable, `<prefix>/alarms/<folders>/<alarm>` für einen Alarm, jeder Name eine Topic-Ebene (ein Leerzeichen, ein Schrägstrich oder ein Platzhalter wird zu `_`). Ändern Sie es nach Belieben: Ein Topic, das noch das vorgeschlagene ist, folgt einer neu gewählten Quelle, eines, das Sie geschrieben haben, bleibt, und das Umbenennen der Quelle behält es. |
| **Zugriff** | **Nur lesen**, der Standard jeder Zeile: Die Station veröffentlicht die Zeile und abonniert für sie nichts. **Lesen und schreiben**: Die Station nimmt außerdem die Werte an, die unter dem Schreib-Topic der Zeile veröffentlicht werden, ihrem Topic gefolgt von `/set`, und schreibt sie in die Quelle ([Zurückschreiben](#writing-back)). Angeboten nur für ein Tag mit Schreibzugriff auf einem Treiber, der schreibt, oder eine Merker-Variable; sonst bleibt es in der Liste, ausgegraut: "Diese Quelle nimmt keinen Schreibzugriff an: Das tun nur ein Tag mit Schreibzugriff oder eine Merker-Variable." Wird ein Alarm gewählt, steht die Zeile wieder auf Nur lesen. Bei Sparkplug B nimmt Lesen und schreiben statt des Schreib-Topics die Werte an, die ein Sparkplug B-Befehl an die Metrik der Zeile sendet. |

Unter den Feldern sagt ein Satz, was die Zeile veröffentlicht:

| Die Karte sagt | Wann |
| --- | --- |
| "Diese Zeile veröffentlicht noch nichts: Wählen Sie ihre Quelle." | Keine Quelle ist gewählt. |
| "Veröffentlicht den Wert, seine Qualität und seine Zeit als JSON, sobald sich der Wert oder die Qualität ändert." | Ein Tag oder eine Variable mit Nur lesen. |
| "Veröffentlicht den Wert, seine Qualität und seine Zeit als JSON, sobald sich der Wert oder die Qualität ändert, und schreibt jeden unter dem Schreib-Topic veröffentlichten Wert in die Quelle: Jeder Schreibzugriff wird mit dem Namen des Brokers im Journal festgehalten." | Ein Tag oder eine Variable mit Lesen und schreiben. |
| "Veröffentlicht als JSON, ob der Alarm aktiv und quittiert ist, seinen Zustand, seine Priorität, seine Meldung und seine Zeit, sobald sich eines davon ändert." | Ein Alarm. |
| "Die Quelle dieser Zeile gibt es nicht mehr, deshalb wird für sie nichts mehr veröffentlicht. Der Broker behält die letzte Nachricht, die er gespeichert hat." | Das Tag, die Variable oder der Alarm wurde gelöscht. |
| "Veröffentlicht den Wert und seine Qualität in Sparkplug B, sobald sich der Wert oder die Qualität ändert." | Sparkplug B: ein Tag oder eine Variable mit Nur lesen. |
| "Veröffentlicht den Wert und seine Qualität in Sparkplug B, sobald sich der Wert oder die Qualität ändert, und schreibt jeden Wert, den ein Sparkplug B-Befehl an seine Metrik sendet, in die Quelle: Jeder Schreibzugriff wird mit dem Namen des Brokers im Journal festgehalten." | Sparkplug B: ein Tag oder eine Variable mit Lesen und schreiben. |
| "Veröffentlicht in Sparkplug B, ob der Alarm aktiv und quittiert ist, seinen Zustand, seine Priorität und seine Meldung, sobald sich eines davon ändert." | Sparkplug B: ein Alarm. |
| "Die Quelle dieser Zeile gibt es nicht mehr, deshalb kündigt sich der Edge-Node ohne sie neu an." | Sparkplug B: Das Tag, die Variable oder der Alarm wurde gelöscht. |

Unter diesem Satz zeigt eine Zeile mit Lesen und schreiben ihr **Schreib-Topic**, das Topic der Zeile gefolgt von `/set`.
Bei Sparkplug B gibt es kein Schreib-Topic: Ein zweiter Satz nennt die Metrik, als die die Zeile veröffentlicht wird, die ihres Sparkplug B-Geräts für ein Tag, die des Edge-Nodes der Station für eine Variable und für einen Alarm die fünf Metriken unter seinem Namen (Active, Acked, State, Priority und Message).

Eine Änderung, die die Liste ablehnt, wird nicht gespeichert: Der Grund steht rot über den
Feldern der Zeile, und die Änderung bleibt auf dem Bildschirm, damit Sie sie korrigieren können.

| Die Karte sagt | Wann |
| --- | --- |
| "Diese Quelle wird auf diesem Broker schon veröffentlicht: Bearbeiten Sie die Zeile, die sie veröffentlicht." | Eine andere Zeile dieses Brokers veröffentlicht die Quelle. |
| "Eine andere Zeile dieses Brokers veröffentlicht schon unter diesem Topic: Geben Sie dieser Zeile ein eigenes Topic." | Zwei Zeilen eines Brokers würden unter einem Topic veröffentlichen. |
| "Auf einem Filter lässt sich nichts veröffentlichen: Das Topic darf + und # nicht enthalten." | Das Topic enthält einen Platzhalter. |
| "Ein Topic, das mit $ beginnt, gehört dem Broker: Schreiben Sie ein anderes." | Das Topic beginnt mit `$`. |
| "Dieses Topic kann nicht übertragen werden: Es enthält ein Zeichen, das kein Topic enthalten darf, oder es ist zu lang." | Ein Steuerzeichen, oder mehr, als ein MQTT-Topic trägt. |
| "Eine Zeile, die Schreibzugriffe annimmt, braucht das Tag oder die Variable, an die sie gehen." | Lesen und schreiben wurde vor einer Quelle gewählt. |
| "Die Quelle kann nicht geschrieben werden: Wählen Sie ein Tag mit Schreibzugriff oder eine Merker-Variable, oder lassen Sie die Zeile schreibgeschützt." | Lesen und schreiben auf einem Alarm, einer Ausdrucksvariable, einem schreibgeschützten Tag oder einem Tag, dessen Treiber nichts schreibt. |
| "Dieses Topic und das Topic einer anderen Zeile dieses Brokers unterscheiden sich nur durch /set, wo eine Zeile Schreibzugriffe annimmt: Geben Sie dieser Zeile ein anderes Topic." | Das Topic einer Zeile ist das Topic einer anderen, gefolgt von `/set`. |
| "Diese Zeile der Liste gibt es nicht mehr. Laden Sie neu und versuchen Sie es erneut." | Die Zeile wurde anderswo gelöscht, während Sie sie bearbeitet haben. |

Was veröffentlicht wird und wann, steht unter [Veröffentlichen](#publishing).

## Gerät {#device}

| Feld | Bedeutung | Standard |
| --- | --- | --- |
| **Broker · fest** | Der Name des Brokers über seiner Adresse, schreibgeschützt: Ein Gerät wird unter seinem Broker angelegt und bleibt dort. "Der Broker hat noch keinen Host" steht an der Stelle der Adresse. "Fehlender Broker" heißt, dass das Gerät seinen Broker verloren hat und nicht gespeichert werden kann: "Ein MQTT-Broker ist erforderlich." | der Broker, unter dem es hinzugefügt wird |
| **Protokoll** | Wie das Gerät veröffentlicht. **Einfaches MQTT**: "Jedes Tag nennt das Topic, das es liest, und bei JSON-Nutzdaten den Pfad zu seinem Wert." **Sparkplug B**: ein Edge-Node oder ein Gerät dahinter: "Jedes Tag nennt eine Metrik so, wie das Birth-Zertifikat des Edge-Nodes sie deklariert; ihr Typ kommt mit der Metrik." Ein Wechsel prüft jedes Tag erneut, weil eine Adresse dann als Topic oder als Metrik gelesen wird. | Einfaches MQTT |
| **Höchste Zeit ohne Nachricht (s)** | Nur einfaches MQTT, 0 bis 86400, 0 heißt nie: "Tags gelten nicht mehr als Messwert, wenn auf ihrem Topic so lange keine Nachricht ankommt. 0: nie, für ein Topic, auf dem nur bei einer Wertänderung veröffentlicht wird. Für ein Gerät, das in festem Takt veröffentlicht, etwa ein Sensor, der alle paar Sekunden meldet, einen Wert eintragen." Außerhalb dieses Bereichs wird das Gerät nicht gespeichert: "Die höchste Zeit ohne Nachricht muss zwischen 0 und 86400 s liegen." Ein Sparkplug B-Gerät hat keine: Sein Death-Zertifikat sagt bereits, wann es verschwunden ist. | 0 |
| **Gruppen-ID** | Nur Sparkplug B: die Gruppe, unter der der Edge-Node veröffentlicht, die Ebene nach `spBv1.0` in seinen Topics. "Ein Sparkplug B-Gerät braucht seine Gruppen-ID." | leer |
| **Edge-Node-ID** | Nur Sparkplug B: der Edge-Node, der die Metriken veröffentlicht, wie sein NBIRTH ihn nennt. "Ein Sparkplug B-Gerät braucht seine Edge-Node-ID." | leer |
| **Geräte-ID** | Nur Sparkplug B: das Gerät hinter dem Edge-Node, wie sein DBIRTH es nennt. Leer, angezeigt als "Der Edge-Node selbst", liest es die eigenen Metriken des Edge-Nodes. | leer |

Das Gerät hat weder Host noch Port, Zugangsdaten oder Abfrageintervall: All das gehört dem
Broker. Jede Sparkplug B-ID ist eine einzige Topic-Ebene: "Eine Sparkplug B-ID darf weder '/' noch '+' oder '#' enthalten."
Ein Broker nennt einen Sparkplug B-Edge-Node oder ein Sparkplug B-Gerät nur einmal, deshalb
wird ein zweites Gerät mit denselben Gruppen-, Edge-Node- und Geräte-IDs auf diesem Broker
abgelehnt: "Das Sparkplug B-Gerät Plant/Line1/Press1 auf dem Broker 'Plant' gehört bereits zum Gerät 'Press'."
Geräte in einfachem MQTT nennen auf dem Broker nichts Eigenes, und zwei von ihnen dürfen
dieselben Topics lesen.

Der Base URI, den die Kopfzeile zeigt, ist die Laufzeitadresse:
`mqtt://<broker id>?host=…&port=…&tls=0&keepAlive=60&clientId=…&mode=plain`, mit `&silence=…`, wenn das Gerät eine höchste Zeit ohne Nachricht einträgt, und für ein
Sparkplug B-Gerät `mode=sparkplug&group=…&node=…`, mit `&device=…` hinter einem Edge-Node. Er
nennt den Broker über seine stabile Identität, nie über seinen Anzeigenamen, und trägt nie
Benutzername oder Passwort.

Die Kopie eines MQTT-Geräts bleibt auf demselben Broker. Eine Sparkplug B-Kopie nimmt die
erste Identität, die kein Gerät dieses Brokers hat: Ihre innerste ID, die Geräte-ID oder, für
die eigenen Metriken des Edge-Nodes, die Edge-Node-ID, wird so nummeriert wie der Name der
Kopie ("Press1 (2)").

## Adressierung des Tags {#tag-addressing}

Das Adressfeld heißt **MQTT-Topic** auf einem Gerät in einfachem MQTT und **Metrik** auf einem
Sparkplug B-Gerät, und es ist erforderlich ("MQTT-Topic ist für diesen Treiber erforderlich.").
Ein einfaches Tag hat drei weitere Felder; eine Sparkplug B-Metrik hat keines, weil sie ihren
Typ selbst mitbringt und über den eigenen Befehl des Protokolls geschrieben wird.

| Feld | Bedeutung | Standard |
| --- | --- | --- |
| **MQTT-Topic** | Das eine Topic, das das Tag liest, z. B. `plant/line1/temperature`. "Ein Tag liest ein einziges Topic, daher darf sein Topic die Platzhalter + und # nicht enthalten." | erforderlich |
| **Wertpfad** | Wo der Wert in JSON-Nutzdaten steht: durch Punkte getrennte Member und Array-Indizes in eckigen Klammern, z. B. `sensors[0].value`. Ein Member, dessen Name einen Punkt oder eine Klammer enthält, wird in Anführungszeichen in eckigen Klammern geschrieben (`['flow.rate']`), und ein führendes `$.` wird angenommen. Leer, angezeigt als "Gesamte Nutzdaten", liest er die gesamten Nutzdaten als Wert. Ein fehlerhafter Pfad: "Schreiben Sie den Wertpfad als durch Punkte getrennte Member und Array-Indizes in eckigen Klammern, z. B. sensors[0].value." | leer |
| **Befehls-Topic** | Wo ein Schreibvorgang veröffentlicht wird. Leer bleibt das Tag schreibgeschützt: Ein Tag, dessen Zugriff schreibt, braucht eines ("Ein schreibbares Tag braucht das Topic, auf dem seine Schreibvorgänge veröffentlicht werden."), und es enthält keinen Platzhalter ("Auf einem Filter lässt sich nichts veröffentlichen: Das Befehls-Topic darf + und # nicht enthalten."). Eine Anlage hört selten auf dem Topic, auf dem sie meldet, deshalb ist es ein eigenes Feld. | leer |
| **Nutzdatenvorlage** | Was ein Schreibvorgang veröffentlicht: JSON mit `{value}` genau einmal, außerhalb von Anführungszeichen, dort, wo der geschriebene Wert steht, z. B. `{"setpoint": {value}}`. Leer, angezeigt als "Der Wert als Text", veröffentlicht sie den Wert als Text. "Die Nutzdatenvorlage enthält {value} genau einmal, dort, wo der geschriebene Wert steht." / "Schreiben Sie die Nutzdatenvorlage als JSON, mit {value} außerhalb von Anführungszeichen dort, wo ein JSON-Wert steht." | leer |
| **Metrik** | Sparkplug B: der Name der Metrik, wie das Birth-Zertifikat ihn deklariert, z. B. `Inputs/Temperature`. | erforderlich |

Die Datentypen sind Boolean, Int16, Int32, Int64, Float, Double, String und DateTime. Die
schreibgeschützte Vorschau der Adresse auf der Leitung ist das Topic, gefolgt von dem, was von
`path`, `command` und `payload` zutrifft
(`plant/line1/temperature?path=sensors[0].value&command=plant/line1/setpoint`), oder der Name
der Metrik; ein Zeichen, das einen Teil beenden würde (`%`, `?`, `&`, `=`, `#`, `+`, ein
Leerzeichen), wird als `%XX` geschrieben.

## Lesen {#reading}

Die Sitzung hält die letzte Nachricht jedes abonnierten Topics, und ein Tag liest daraus:

| Situation | Tag in einfachem MQTT | Sparkplug B-Tag |
| --- | --- | --- |
| Der Wert | Die letzte Nachricht auf dem Topic: die gesamten Nutzdaten als Text oder der JSON-Wert am Wertpfad, in den Typ des Tags umgewandelt. | Der Wert der Metrik aus der letzten Birth- oder Datennachricht des Edge-Nodes. |
| Sein Zeitstempel | Wann die Nachricht ankam. Eine Nachricht, die der Herausgeber gehalten hat, liefert den ersten Wert, sobald die Station abonniert. | Der eigene Zeitstempel der Metrik. |
| Noch nichts empfangen | Das Tag wartet: kein Wert und kein Fehler, wie bei jedem Treiber vor seiner ersten Antwort. Ein Topic, dessen Herausgeber nicht hält, hat keinen Wert, bis er erneut veröffentlicht. Ist eine **Höchste Zeit ohne Nachricht (s)** eingetragen, dauert das Warten so lange ab dem Moment, in dem die Station zu hören begann; danach schlägt der Lesevorgang des Tags fehl. | Ebenso, bis das Birth-Zertifikat ankommt; die Station bittet den Edge-Node, sich neu anzukündigen. |
| Herausgeber verstummt, Broker weiter erreichbar | Ist eine **Höchste Zeit ohne Nachricht (s)** eingetragen, schlägt der Lesevorgang eines Tags fehl, dessen Topic länger keine Nachricht hatte, und die Regel des Tags für [ein Gerät, das nicht geantwortet hat](connector-value-pipeline#the-device-did-not-answer) entscheidet, was es zeigt; die nächste Nachricht bringt den Wert zurück. Die Zeit zählt ab der Ankunft der letzten Nachricht, auch einer gehaltenen. Bei 0 behält das Tag den zuletzt empfangenen Wert. | Trifft nicht zu: Das Death-Zertifikat sagt es. |
| Eine Nachricht, die das Tag nicht lesen kann | Ein fehlgeschlagener Lesevorgang dieses Tags, mit dem Grund: eine leere Nachricht, Nutzdaten, die unter einem Wertpfad kein JSON sind, nichts am Pfad, oder ein Wert, den der Typ nicht fassen kann. | Ein fehlgeschlagener Lesevorgang dieses Tags: eine Metrik, die das Birth-Zertifikat nicht deklariert, oder ein Wert, den ihr Typ nicht fassen kann. |
| Broker nicht erreichbar | Jedes Gerät des Brokers ist getrennt, und seine Tags schlagen fehl wie die jedes Geräts. | Ebenso. |
| Ein Death-Zertifikat (NDEATH, DDEATH) | Trifft nicht zu. | Der Edge-Node und seine Geräte, oder nur dieses eine Gerät, haben keinen Wert, bis sie neu geboren werden; jedes andere Gerät des Brokers läuft weiter. |

Ein Boolean-Tag nimmt `true` oder `false`, `1` oder `0`, `on` oder `off`. Ein ganzzahliges Tag
nimmt eine gebrochene Zahl gerundet an und lehnt eine außerhalb seines Bereichs ab. Ein
DateTime-Tag nimmt Text nach ISO 8601 oder Unix-Millisekunden. Ein String-Tag nimmt den Text,
wie er ist, und ein JSON-Objekt oder -Array als rohes JSON. Eine Sparkplug B-Metrik eines
vorzeichenlosen Typs wird in den nächstbreiteren vorzeichenbehafteten Typ gelesen (UInt8 als
Int16, UInt16 als Int32, UInt32 und UInt64 als Int64), damit ihr ganzer Bereich gelesen wird.

## Schreiben {#writing}

Ein Schreibvorgang läuft durch denselben Trichter wie der jedes anderen Treibers: Das
Schreibfeld nimmt den technischen Wert, und die Umrechnungsstufen werden umgekehrt, bevor der
Rohwert veröffentlicht wird (siehe [Connector](connector)).

| Tag | Was veröffentlicht wird | QoS | Was der Schreibvorgang meldet |
| --- | --- | --- | --- |
| Einfaches MQTT | Der Wert auf dem **Befehls-Topic** des Tags, als Text (`21.5`, `true`, der Text selbst, ein Datum nach ISO 8601), oder in die **Nutzdatenvorlage** als JSON-Wert eingesetzt (eine Zahl als Zahl, ein boolescher Wert als `true` oder `false`, ein Text in Anführungszeichen und maskiert). | 1, nicht gehalten | Erledigt, wenn der Broker ihn bestätigt; abgelehnt, mit dem Grund des Brokers, wenn ein MQTT-5-Broker ihn zurückweist; keine Antwort, wenn keine Bestätigung rechtzeitig kommt. |
| Sparkplug B | Ein NCMD (eine Metrik des Edge-Nodes) oder ein DCMD (eine Metrik eines Geräts dahinter) mit der Metrik, unter dem Alias, den ihre Geburt ihr gab, und mit dem Typ, den die Geburt deklarierte. | 0, nicht gehalten, wie die Sparkplug B-Spezifikation es für Befehle verlangt | Erledigt, sobald gesendet. Der Edge-Node antwortet, indem er den neuen Wert veröffentlicht, und den liest das Tag als Nächstes. |

Solange der Broker nicht erreichbar ist oder der Edge-Node oder das Gerät seinen Tod
angekündigt hat, wird ein Schreibvorgang als getrennt abgelehnt, und nichts wird gesendet. Ein
Sparkplug B-Schreibvorgang auf eine Metrik, die das Birth-Zertifikat nicht deklariert, wird
abgelehnt, weil der Edge-Node ihn nicht annähme, ebenso ein Wert, den der Typ der Metrik nicht
tragen kann. Ein Schreibvorgang wird nie gehalten: Ein gehaltener Sollwert würde von jedem
Abonnenten, der sich später verbindet, erneut angewendet.

## Veröffentlichen {#publishing}

Dieser Abschnitt beschreibt das **Veröffentlichungsformat** auf **JSON**; Sparkplug B hat den folgenden Abschnitt.

Jede Zeile der [Karte Veröffentlichen](#the-publish-card) eines Brokers wird unter ihrem Topic
veröffentlicht, als Retained-Nachricht, mit QoS 1, über die Verbindung, die die Geräte des Brokers
nutzen: Die Station öffnet nie eine zweite Verbindung zu einem Broker. Ein Broker, der nur
veröffentlicht, braucht kein Gerät. Er bleibt unter dem Treiber MQTT, und sein Zustand
(Verbindung wird aufgebaut…, Verbunden, Nicht erreichbar) ist der dieser Verbindung. Er
veröffentlicht, solange er aktiviert ist und die Liste Zeilen hat; einen eigenen Schalter hat er nicht.

| Quelle | Nachricht (JSON) |
| --- | --- |
| Tag | `{"value": 21.5, "quality": "good", "timestamp": "2026-10-04T12:30:15.250Z"}`: der technische Wert, den das Tag zeigt; `quality` ist `good` für einen Lesevorgang, der angekommen ist, `bad` mit `value` null für einen, der es nicht ist, und `uncertain` für einen Ersatzwert, für den zuletzt gehaltenen Wert und für Lesevorgänge, die ausbleiben (der zuletzt veröffentlichte Wert bleibt); der Zeitstempel des Lesevorgangs, in UTC. |
| Logic-Variable | Dieselben Mitglieder: der Wert der Variable und `good`, solange sie gut ist, sonst `null` und `bad`; der Zeitstempel ihres letzten Schreibens oder ihrer letzten Berechnung. |
| Alarm | `{"active": true, "acked": false, "state": 1, "priority": "High", "message": "Oven above 80 °C", "timestamp": "2026-10-04T12:30:15.250Z"}`: ob er aktiv und quittiert ist, `state` als Zahl (0 normal, 1 aktiv und unquittiert, 2 aktiv und quittiert, 3 gegangen und unquittiert), die Priorität mit ihrem Namen (Critical, High, Medium, Low), die Meldung (leer, wenn keine) und der Zeitstempel seines letzten Übergangs, so wie ihn der [OPC UA-Server](connector-opcua-served-nodes#where-a-client-finds-each-source) bereitstellt. |

Ein Wert reist als sein JSON-Typ: eine Zahl, `true` oder `false`, Text, ein Datum mit Uhrzeit als
ISO-8601-Text; eine Zahl, die JSON nicht trägt (NaN, unendlich), reist als `null`. Ein Tag eines
deaktivierten Geräts veröffentlicht `null` und `bad`.

| Situation | Was veröffentlicht wird |
| --- | --- |
| Der Wert oder die Qualität ändert sich | Diese Zeile, fünfmal je Sekunde geprüft. Ein Tag, das erneut mit demselben Wert gelesen wird, wird nicht erneut veröffentlicht: Der Zeitstempel allein ist keine Änderung. |
| Die Verbindung wird aufgebaut oder erneut aufgebaut | Jede Zeile, mit ihrem aktuellen Zustand. |
| Der Broker ist nicht erreichbar | Nichts, und nichts wartet in einer Warteschlange: Kommt der Broker zurück, wird jede Zeile mit ihrem Zustand in diesem Moment veröffentlicht. |
| Der Broker lehnt eine Nachricht ab oder bestätigt sie nicht | Sie wird nach 30 Sekunden erneut versucht. Das Journal hält es im Bereich Connector, Komponente `MQTT publication` fest, einmal und dann alle paar Minuten in einer Zusammenfassung, solange es andauert. |
| Eine Quelle wird gelöscht | Nichts mehr; der Broker behält die letzte Nachricht, die er aufbewahrt hat. |
| Eine Zeile wird gelöscht | Nichts mehr; ihre aufbewahrte Nachricht bleibt unter dem Topic, bis dort etwas anderes veröffentlicht wird. |

Die Station liest, was sie veröffentlicht, und berechnet nichts dafür: den letzten Lesevorgang
eines Tags, den Wert einer Variable, den Zustand eines Alarms. Sie abonniert kein Topic einer Zeile mit Nur lesen, also erreicht eine Nachricht, die ein anderes System dort sendet, die Station nie; eine Zeile mit Lesen und schreiben nimmt Werte unter ihrem Schreib-Topic an ([Zurückschreiben](#writing-back)). Ein
Agent liest die Listen mit `mqtt_publish_list` und ändert sie mit `mqtt_publish_upsert` und
`mqtt_publish_delete` ([Werkzeuge](agent-tools#connector--configure)):

```text
mqtt_publish_upsert(brokerId: "<id from mqtt_broker_list>", source: "Connector.Simulated.Oven.Temperature")
mqtt_publish_upsert(brokerId: "<id from mqtt_broker_list>", source: "Alarms.Oven.HighTemperature", topic: "plant/oven/alarms/high")
mqtt_publish_upsert(id: "<id from mqtt_publish_list>", access: "ReadAndWrite")
mqtt_publish_list()
```

## Veröffentlichen in Sparkplug B {#publishing-in-sparkplug-b}

Steht **Veröffentlichungsformat** auf **Sparkplug B**, veröffentlicht der Broker dieselbe Liste nach der
Sparkplug B-Spezifikation, mit der Station als Edge-Node: Ein Sparkplug B-Host, etwa die MQTT Engine von
Ignition, führt die Station unter ihrer Gruppe und ihrem Edge-Node auf, jedes Gerät darunter und jede
Metrik mit ihrem Typ, ohne eine von Hand gebaute Zuordnung. Die Verbindung ist dieselbe, die die Geräte
des Brokers nutzen, wie bei JSON.

| Name | Was es ist |
| --- | --- |
| Gruppe | **Gruppen-ID**, `GanterLab`, solange sie leer ist. |
| Edge-Node | Der Name der Station, jedes `/`, `+` und `#` durch `_` ersetzt (die drei Zeichen, die eine Sparkplug B-ID nicht enthalten darf). |
| Gerät | Jedes Connector-Gerät mit einer Zeile eines seiner Tags, auf dieselbe Weise benannt. |
| Metrik eines Tags | Der Name des Tags, auf seinem Gerät. |
| Metrik einer Variable | `Logic/<folders>/<variable>`, auf dem Edge-Node. |
| Metriken eines Alarms | Fünf, auf dem Edge-Node, unter `Alarms/<folders>/<alarm>/`: `Active` und `Acked` (Boolean), `State` (eine Zahl: 0 normal, 1 aktiv und unquittiert, 2 aktiv und quittiert, 3 gegangen und unquittiert), `Priority` und `Message` (Text). |

Ein `/` innerhalb eines Namens wird zu `_`, die Ordner sind also die einzigen Ebenen. Zwei Geräte oder
zwei Metriken, deren Namen gleich werden, erhalten `_2`, `_3` in der Reihenfolge ihrer eigenen Namen. Die
Zeilen behalten ihre Topics, unter denen bei Sparkplug B nichts veröffentlicht wird und unter denen die
Liste wieder veröffentlicht, sobald der Broker zu JSON zurückkehrt.

| Nachricht | Wann |
| --- | --- |
| NDEATH, der Tod des Edge-Nodes | Dem Broker bei jedem Öffnen der Verbindung als ihr letzter Wille übergeben, damit der Broker ihn veröffentlicht, wenn die Station wegfällt. Die Station veröffentlicht ihn auch selbst, bevor sie aufhört zu veröffentlichen: der Broker zurück auf JSON, deaktiviert oder gelöscht, die Liste geleert, die Gruppe oder der Name der Station geändert, die Runtime gestoppt. |
| NBIRTH, die Geburt des Edge-Nodes | Bei jedem Öffnen der Verbindung, wenn ein Host eine Wiedergeburt anfordert (`Node Control/Rebirth`) und wenn eine Variable oder ein Alarm hinzukommt, wegfällt oder umbenannt wird: jede Metrik des Edge-Nodes mit ihrem aktuellen Wert, mit `bdSeq` und `Node Control/Rebirth`. |
| DBIRTH, die Geburt eines Geräts | Nach jedem NBIRTH für jedes Gerät und für ein Gerät, das in die Liste kommt: jedes Tag des Geräts mit seinem aktuellen Wert. |
| NDATA, DDATA | Fünfmal pro Sekunde die Metriken, deren Wert oder Qualität sich geändert hat: eine Nachricht für den Edge-Node, eine pro Gerät. |
| DDEATH, der Tod eines Geräts | Wenn die letzte Zeile eines Geräts die Liste verlässt, und bevor ein Gerät, dessen Tags sich geändert haben, neu geboren wird. |

Jede Nachricht außer dem NDEATH geht mit QoS 0 hinaus, nie aufbewahrt. Die Sequenznummer `seq` beginnt mit
jedem NBIRTH bei 0 und zählt jede Nachricht danach bis 255, dann beginnt sie von vorn; `bdSeq` zählt die
Verbindungen, sodass NBIRTH und NDEATH einer Verbindung dieselbe Nummer tragen. Solange der Broker nicht
erreichbar ist, wartet nichts in einer Warteschlange.

| Typ der Quelle | Sparkplug B-Typ |
| --- | --- |
| `Boolean` | `Boolean` |
| `SByte`, `Byte` | `Int8`, `UInt8` |
| `Int16`, `UInt16` | `Int16`, `UInt16` |
| `Int32`, `UInt32` | `Int32`, `UInt32` |
| `Int64`, `UInt64` | `Int64`, `UInt64` |
| `Float`, `Double` | `Float`, `Double` |
| `String` | `String` |
| `DateTime` | `DateTime` |
| `Guid`, `ByteString` | `UUID`, `Bytes` |

Ein Tag wird mit seinem eigenen Typ veröffentlicht, eine Variable mit dem Typ, mit dem der [OPC UA-Server](connector-opcua-served-nodes#where-a-client-finds-each-source) sie bereitstellt (eine ganze Zahl als Int64, eine reelle Zahl als Double, ein Darstellungswert als Text). Jede Metrik trägt ihre Qualität in der Eigenschaft `Quality`, der Konvention, die Sparkplug B-Hosts lesen: 192 gut, 64 unsicher (mit dem zuletzt veröffentlichten Wert, wenn die Lesung ausblieb), 0 schlecht (die Metrik hat dann keinen Wert).

| Befehl | Was die Station tut |
| --- | --- |
| NCMD `Node Control/Rebirth` | Veröffentlicht NBIRTH und jedes DBIRTH erneut, mit den aktuellen Werten. |
| NCMD oder DCMD mit der Metrik einer Zeile mit Lesen und schreiben | Schreibt den Wert in die Quelle, wie es [Zurückschreiben](#writing-back) tut: in der Reihenfolge, in der die Befehle ankommen, im Journal mit dem Ursprung `MQTT <broker name>` festgehalten. |
| Jede andere Metrik, ein Befehl ohne Wert oder einer, den der Broker als aufbewahrte Nachricht übergibt | Nichts wird geschrieben; das Journal hält es im Bereich Connector, Komponente `MQTT publication` fest. |

Die Station hört Befehle an den Edge-Node immer, damit ein Host eine Wiedergeburt anfordern kann, und
Befehle an ein Gerät nur, solange eine seiner Zeilen Lesen und schreiben hat. Das Umstellen eines Brokers
auf Sparkplug B öffnet seine Verbindung einmal neu, damit der Broker den letzten Willen des Edge-Nodes hält;
die Geräte des Brokers überstehen das wie jede Wiederverbindung. Die Station ist ein Edge-Node und keine
primäre Host-Anwendung: Sie wartet nicht auf die STATE-Nachricht eines Hosts, bevor sie geboren wird.

```text
mqtt_broker_upsert(id: "<id from mqtt_broker_list>", publishFormat: "SparkplugB", sparkplugGroupId: "Plant1")
mqtt_publish_list()
```

## Zurückschreiben {#writing-back}

Eine Zeile einer [Karte Veröffentlichen](#the-publish-card) mit **Lesen und schreiben** nimmt Werte
unter ihrem Schreib-Topic an, dem Topic der Zeile gefolgt von `/set`: Ein Cloud-Dashboard, das
`plant/oven/setpoint` liest, sendet einen neuen Sollwert unter `plant/oven/setpoint/set`. Die
Station schreibt ihn so, wie ein Client ihres [Modbus-Servers](connector-modbus-server) oder ihres
[OPC UA-Servers](connector-opcua-served-nodes) eine Zeile mit Lesen und schreiben schreibt.

| Situation | Was geschieht |
| --- | --- |
| Eine Zeile wird auf Lesen und schreiben gestellt | Die Station abonniert ihr Schreib-Topic mit QoS 1 über die Verbindung, die die Geräte des Brokers nutzen, und erneut bei jedem Aufbau dieser Verbindung. Eine Zeile mit Nur lesen wird nicht abonniert, also erreicht eine Nachricht unter ihrem Schreib-Topic die Station nie. |
| Unter dem Schreib-Topic kommt eine Nachricht an | `{"value": 65}` oder der bloße Wert (`65`, `true`, `Rezept A`) wird in der Reihenfolge, in der die Nachrichten ankommen, in die Quelle geschrieben: ein Tag auf demselben Weg wie der Schreibzugriff eines Bedieners, eine Merker-Variable unmittelbar. Eine JSON-Zahl, `true` oder `false` und ein JSON-Text kommen als das an, was sie tragen; was kein JSON ist, wird als Text gelesen. Der Wert wird wie jeder Schreibzugriff in den Typ der Quelle umgerechnet, und ein Wert, den der Typ nicht tragen kann, wird abgelehnt. |
| Die Nachricht trägt keinen Wert | Nichts wird geschrieben: eine leere Nachricht, `null`, ein JSON-Objekt ohne `value`, ein Array. |
| Der Broker übergibt die Nachricht, die er aufbewahrt hat | Nichts wird geschrieben. Der Broker übergibt sie, wenn die Station abonniert, und ein Sollwert, der dort seit einer Stunde liegt, ist kein Wert, den jemand jetzt sendet. Ein Wert, der veröffentlicht wird, während die Station zuhört, wird geschrieben, aufbewahrt oder nicht. |
| Die Quelle nimmt keinen Schreibzugriff mehr an | Nichts wird geschrieben: ein Tag, das wieder auf Nur lesen steht, eine gelöschte Variable. |
| Die Zeile wird wieder auf Nur lesen gestellt, bekommt ein anderes Topic oder wird gelöscht, oder der Broker wird deaktiviert | Die Station hört innerhalb eines Augenblicks auf, dieses Schreib-Topic abzuhören, und eine Nachricht, die in der Zwischenzeit ankommt, schreibt nichts. |

Das Journal hält jeden Schreibzugriff mit der Herkunft `MQTT <Name des Brokers>` im Bereich
Connector fest, so wie den Schreibzugriff eines Bedieners. Eine Nachricht, die nicht geschrieben
wurde, hält es im Bereich Connector, Komponente `MQTT publication`, fest, einmal und dann alle paar
Minuten in einer Zusammenfassung, solange sie sich wiederholt.

Benutzername und Passwort des Brokers sind der einzige Schutz: Wen der Broker unter einem
Schreib-Topic veröffentlichen lässt, der kann diese Quelle ändern, und auf einem Cloud-Broker, den
sich mehrere teilen, sind das mehr Leute als die Anlage. Geben Sie dem Konto des Dashboards auf dem
Broker nur die Topics, die es braucht. Auf einem Broker in Sparkplug B nehmen
dieselben Zeilen Sparkplug B-Befehle (NCMD, DCMD) statt eines Schreib-Topics an ([Veröffentlichen in Sparkplug B](#publishing-in-sparkplug-b)).

```text
"C:\Program Files\mosquitto\mosquitto_pub" -h localhost -u dashboard -P <password> -t plant/oven/setpoint/set -m 65
```

## Sicherheit {#security}

Mit **TLS verwenden** wird das Zertifikat des Brokers auf einem von zwei Wegen angenommen:
Seine Kette und sein Hostname bestehen die Prüfung gegen den Windows-Zertifikatspeicher, wie
bei jeder HTTPS-Verbindung dieses Computers, oder Sie haben genau dieses Zertifikat unter
[Anlagenzugriff](#equipment-access) auf der Seite dieses Treibers freigegeben. Ein Broker,
dessen Zertifikat von einer eigenen Zertifizierungsstelle stammt, gilt als vertrauenswürdig,
sobald diese Stelle im Windows-Speicher installiert ist, und einer mit einem selbstsignierten
Zertifikat braucht nichts installiert, sobald sein Zertifikat freigegeben ist. Der Widerruf
wird nicht geprüft, und nichts nimmt ein Zertifikat ungesehen an: Ein unbekanntes wird
abgewiesen, der Broker bleibt nicht erreichbar, mit dem Grund, und seine Geräte warten auf
die Freigabe. Das Passwort reist innerhalb der TLS-Verbindung; ohne TLS reist es im Klartext,
wie die Karte warnt.

## Anlagenzugriff {#equipment-access}

Ein Broker mit einem selbstsignierten Zertifikat oder einem, das eine eigene Stelle
ausgestellt hat, legt ein Zertifikat vor, für das keine in Windows installierte Wurzel bürgt.
Diese Wurzel muss auf diesem Rechner nicht installiert werden. Mit **TLS verwenden** wird die
erste Verbindung abgewiesen, der Broker bleibt nicht erreichbar, mit dem Grund, seine Geräte
zeigen im Baum und auf ihren Seiten **Wartet auf Freigabe des Zertifikats**, deren
Schaltfläche **Zertifikat prüfen** diese Karte auf dem Zertifikat öffnet, und das Zertifikat
wartet unter **Anlagenzugriff** am Ende der Seite des MQTT-Treibers, derselben Karte wie auf
der Seite des OPC UA-Treibers, bis Sie entscheiden:

| Gruppe | Was sie zeigt | Was Sie tun können |
|---|---|---|
| Wartet auf Freigabe | Jedes abgewiesene Zertifikat unter dem Namen, den es behauptet: sein SHA-256-Fingerabdruck, die Adresse des Brokers, unter der es angetroffen wurde, wann es zuletzt versucht wurde und wie oft, und seine Details (Antragsteller, Aussteller, Domänennamen, Gültigkeitsdaten). Das Zertifikat, das **Zertifikat prüfen** eines Geräts geöffnet hat, ist als Zur Prüfung ausgewählt markiert. | **Freigeben** nimmt das Zertifikat ab dem nächsten Verbindungsversuch der Sitzung an. **Sperren** weist es weiter ab, ohne es hier erneut aufzuführen. **Alle ausstehenden Zertifikate verwerfen** leert die Liste, ohne etwas freizugeben oder zu sperren. |
| Freigegebene Anlagen | Die Zertifikate, die Sie freigegeben oder importiert haben, mit der Angabe, wer wann entschieden hat, und der Adresse des Brokers, unter der jedes zuletzt angetroffen wurde. | **Freigabe zurücknehmen** schließt die Sitzung des Brokers und bringt sein Zertifikat in die Liste zurück. **Zertifikat importieren** gibt eine öffentliche Zertifikatsdatei, die Sie bereits haben (.der, .cer, .crt oder .pem), vor der ersten Verbindung frei. |
| Gesperrte Anlagen | Die Zertifikate, die Sie gesperrt haben. Ein gesperrtes Zertifikat wird abgewiesen, auch wenn Windows ihm vertraut. | **Entsperren** bringt das Zertifikat in die Liste zurück, ohne es freizugeben. |

Prüfen Sie den Fingerabdruck mit derjenigen Person, die den Broker betreut, bevor Sie das
Zertifikat freigeben. Eine Freigabe nimmt genau dieses Zertifikat an und kein anderes, und nur
innerhalb seiner Gültigkeitsdaten; sie steht für die Wurzel ein, die Windows fehlt, und für den
Namen, den das Zertifikat trägt, sodass sich ein Broker, der über seine IP-Adresse erreicht
wird, verbindet, obwohl sein Zertifikat einen anderen Host nennt, und sonst wird am Zertifikat
nichts gelockert. Antwortet der Broker an einer Adresse, deren Zertifikat Sie freigegeben
haben, mit einem anderen, hören seine Geräte auf zu lesen, das neue wartet hier, und die
Station meldet "Zertifikat geändert: `<Name>`" mit einer Schaltfläche **Prüfen**. Eine
Gerätesuche auf dem Broker über die Karte Geräte suchen trifft auf dieselben Entscheidungen.
Ein Zertifikat, dem Windows bereits vertraut, wird wie bisher angenommen und erscheint hier
nie; nichts wird automatisch freigegeben.

Die Ursache des Brokers nennt den Grund statt eines namenlosen TLS-Fehlers: "Das Zertifikat des
Brokers unter `<Host>:<Port>` (die ersten 16 Zeichen des Fingerabdrucks) wartet unter
Anlagenzugriff auf der Seite des MQTT-Treibers auf Ihre Freigabe. Das Lesen beginnt, sobald
Sie es freigeben." Ein gesperrtes liest "…ist an dieser Station gesperrt. Prüfen Sie es unter
Anlagenzugriff auf der Seite des MQTT-Treibers." Ein Zertifikat außerhalb seiner
Gültigkeitsdaten, widerrufen oder mit gebrochener Signatur wird mit diesem Grund abgewiesen und
nie aufgeführt, weil keine Freigabe es einwandfrei macht.

Die Entscheidungen liegen im Datenordner der Station unter `ua\pki\mqtt` und überstehen einen
Neustart. Die Befehle werden nur einer Rolle gezeichnet, die den Connector konfigurieren darf,
und sie wirken nur im eigenen Fenster der Station: Ein Browser auf einem anderen Gerät liest
die Karte, ohne sie zu ändern, und kein Werkzeug eines Agenten gibt ein Zertifikat frei
(`connector_browse` meldet die Geräte des Brokers mit `awaitingCertificate`). Die Liste hält
bis zu 100 Zertifikate, die auf Freigabe warten; ist sie voll, wird ein neues weiter
abgewiesen, aber nicht aufgeführt, und die Karte sagt das.

## Den Broker vorbereiten {#prepare-the-broker}

Ein Broker muss Verbindungen vom Rechner der Station annehmen und die Anmeldung der Station
annehmen. Eclipse Mosquitto 2, der verbreitetste Broker, tut ab Werk keines von beiden: Ohne
Listener in seiner mosquitto.conf hört er nur auf dem eigenen Rechner, und sobald er einen hat,
weist er einen Client ohne Benutzernamen ab. MQTT sagt nicht, welcher Broker geantwortet hat,
deshalb nennt die Station Mosquitto als den häufigen Fall, nie als Gewissheit.

| Der Broker antwortet | Was die Seite des Brokers sagt | Was es ändert |
| --- | --- | --- |
| Sein Rechner weist den Port ab | Der Broker nimmt nur Verbindungen vom eigenen Rechner an | In der mosquitto.conf die Zeile listener, gefolgt vom Port (listener 1883), dann ein Neustart des Brokers; der Port in der Firewall seines Rechners erlaubt |
| Er weist einen Client ohne Benutzernamen ab | Der Broker nimmt keinen Client ohne Benutzernamen an | Benutzername und Passwort auf der Karte Verbindung zum Broker, mit einem Konto des Brokers; bei Mosquitto 2 wird dieses Konto mit mosquitto_passwd angelegt und mit password_file in der mosquitto.conf genannt, oder anonyme Clients werden mit allow_anonymous true zugelassen |
| Er weist Benutzername oder Passwort ab | Die eigene Ablehnung des Brokers, mit Verweis auf Benutzername und Passwort auf der Karte Verbindung zum Broker | Das Konto, auf dem Broker oder auf der Karte |

Die ersten beiden werden auf der Seite des Brokers gesagt, anstelle seines englischen Fehlers,
mit diesen Schritten und dem Port; seine Geräte verweisen weiter auf den Broker. Der Hinweis
verschwindet von selbst, sobald sich die Sitzung verbindet. Die Markierung im Baum und das
Protokoll behalten die englische Ursache, die mit denselben Mosquitto-Schritten endet.

## Einen Broker installieren {#installing-a-broker}

Die Station braucht einen Broker, mit dem sie sich verbindet, und die Anlage ebenso. Wo Sie
keinen haben, ist Eclipse Mosquitto ein kleiner Broker, der als Windows-Dienst läuft:

1. Laden Sie das Windows-Installationsprogramm von der Download-Seite von mosquitto.org und
   führen Sie es aus. Es installiert den Dienst **Mosquitto Broker** in
   `C:\Program Files\mosquitto`.
2. Ab Werk antwortet Mosquitto nur auf dem Computer, auf dem es läuft. Um die Anlagen im Netz
   hereinzulassen, ergänzen Sie in der `mosquitto.conf` dieses Ordners einen Listener und eine
   Passwortdatei:

   ```
   listener 1883
   password_file C:\Program Files\mosquitto\passwd
   ```

   Legen Sie die Datei mit dem Konto an, das Station und Anlagen benutzen werden (der Befehl
   fragt nach dem Passwort):

   ```
   "C:\Program Files\mosquitto\mosquitto_passwd" -c "C:\Program Files\mosquitto\passwd" station
   ```

3. Starten Sie den Dienst in einer Eingabeaufforderung als Administrator neu, und lassen Sie
   in der Windows Defender Firewall TCP-Port 1883 für das Netz der Anlagen eingehend zu:

   ```
   net stop mosquitto
   net start mosquitto
   ```

4. Tragen Sie auf der Seite des Brokers `localhost` als **Hostadresse** ein, wenn der Broker
   auf dem Computer der Station selbst läuft, sonst die Adresse dieses Computers, **Port**
   1883 und das angelegte Konto, dann **Aktivieren**.

Um ein einfaches Tag auszuprobieren, bevor die Anlagen verbunden sind, veröffentlichen Sie aus
demselben Ordner einen gehaltenen Testwert und richten das **MQTT-Topic** eines Tags darauf:

```
"C:\Program Files\mosquitto\mosquitto_pub" -h localhost -u station -P <password> -t plant/line1/temperature -m 21.5 -r
```

## Grenzen, die man kennen sollte {#limits-worth-knowing}

- Der Treiber MQTT ist ein Client, kein Broker: Anlagen und Station verbinden sich mit einem
  Broker, dem eigenen [MQTT-Broker](connector-mqtt-broker) der Station oder einem anderen.
- Die Karte Veröffentlichen eines Brokers geht als JSON oder als Sparkplug B hinaus, nie beides
  zugleich. Bei Sparkplug B ist die Station ein Edge-Node, keine primäre Host-Anwendung, und
  nutzt keine Aliase, Vorlagen oder historischen Werte.
- Die Station ist keine Sparkplug B-Host-Anwendung: Sie veröffentlicht keine STATE-Nachricht.
  Ein Edge-Node, der vor dem Veröffentlichen auf einen primären Host wartet, bleibt stumm.
- Einfaches MQTT sagt nichts über einen Herausgeber, der verstummt ist: Ein einfaches Tag
  behält den zuletzt empfangenen Wert, solange die Verbindung zum Broker steht, datiert auf
  dessen Ankunft, es sei denn, sein Gerät trägt eine **Höchste Zeit ohne Nachricht (s)** ein. Ein Topic, auf dem nur
  bei einer Wertänderung veröffentlicht wird, kann einen verstummten Herausgeber nicht von einem
  gleichbleibenden Wert unterscheiden, deshalb behält sein Gerät 0. Sparkplug B sagt es, über
  das Death-Zertifikat.
- Die Sitzung beginnt sauber: Was veröffentlicht wurde, während die Station nicht verbunden
  war, wird nicht nachgeliefert, und die gehaltene Nachricht eines Topics gibt seinem Tag
  wieder einen Wert.
- Ein Tag liest ein Topic, nie einen Filter, und einen Wert daraus; eine Sparkplug B-Metrik,
  die ein Array, ein Datensatz, ein Template oder ein Eigenschaftssatz ist, wird nicht
  gelesen.
- Nur TCP, mit oder ohne TLS: kein MQTT über WebSockets, kein Client-Zertifikat und kein
  Broker älter als MQTT 3.1.1.
- Ein Gerät lässt sich nicht zu einem anderen Broker verschieben: Legen Sie es unter dem
  anderen Broker an und löschen Sie das alte.
