# Logic

> Die Seite Logic, ihre Spalte Adressraum, die Ordner, die Befehlsleiste, der Zyklus und der Schreibkanal hinter jedem Bereich und die drei Berechtigungen, die entscheiden, was die Seite zeichnet.

Logic ist der dritte Eintrag der Navigationsleiste. Sie öffnet sich für jede Rolle mit **Logic anzeigen**, und ihre Kopfzeile liest "Variablen (abgeleitete oder schreibbare Werte) und Aktionen (Skripte, die sie schreiben) über dem Adressraum festlegen." Sie ist eine Master-Detail-Seite ([wie die Seiten funktionieren](app-conventions)): links eine Spalte mit der Überschrift **Adressraum**, rechts eine Befehlsleiste und ein Detailbereich. Alles, was Sie hier bearbeiten, wird beim Tippen automatisch gespeichert; es gibt auf der ganzen Seite keine Schaltfläche zum Speichern.

## In diesem Bereich {#in-this-area}

| Seite | Inhalt |
| --- | --- |
| [Der Adressraum](logic-address-space) | Die sieben reservierten Wurzeln, wie eine Adresse geschrieben und bereinigt wird, das Filterfeld und die drei Wege, eine Adresse einzugeben. |
| [Variablen](logic-variables) | Der Editor einer Variablen: Identität und Adresse, die Arten Ausdruck und Merker, die Karte Wert, Wert setzen. |
| [Ausdrücke](logic-expressions) | Die Sprache der Ausdrücke, die Lesefläche eines Punkts, die Regeln, die der Auswerter erzwingt, der Editor für Skripte. |
| [Aktionen](logic-actions) | Der Editor einer Aktion, was ein Skript schreiben darf, jede Prüfmeldung, Ausführen und Aktivieren/Deaktivieren. |
| [Auslöser](logic-triggers) | Der Editor eines Auslösers und der Zeitplan der Intervalle. |
| [Alarme](logic-alarms) | Der Editor eines Alarms, der Zustandsautomat, die Meldung, Quittieren und Alle quittieren. |
| [Von anderen Seiten](logic-from-other-pages) | Die Wurzeln System, Server, Connector und Process, der Bereich eines Punkts und der Hinweis, der die Seite nennt, die sie bearbeitet. |

Die Wurzel **Assets** derselben Spalte ist eine Gruppe für sich: [Ressourcen](logic-assets) behandelt Images, Icons, Colors, Symbols und Connection types.

## Die Spalte Adressraum {#the-address-space-column}

Die Spalte führt die Wurzeln des Adressraums unter zwei Überschriften auf. **Hier festgelegt** enthält, was diese Seite anlegt und bearbeitet: **Variables**, **Alarms**, **Actions**, **Triggers** und **Assets**. **Von anderen Seiten** enthält, was sie nur zeigt: **System**, **Server**, **Connector** und **Process**. Jede Wurzel unter der ersten Überschrift trägt eine Anzahl (Variables und Alarms zählen ihre Definitionen, Actions und Triggers ihre, Assets die Summe ihrer fünf Kategorien), und die Wurzel Alarms, jeder Alarmordner und jede Alarmzeile tragen einen farbigen Punkt mit der schlimmsten Priorität, die sie halten und die aktiv ist oder auf Quittierung wartet; der Punkt räumt sich in dem Augenblick weg, in dem der Alarm beantwortet ist.

Der Baum ist träge: Ein Zweig lädt, wenn Sie ihn aufklappen. Laufende Werte werden nie im Baum gezeichnet; der Detailbereich des gewählten Knotens zeigt sie, zweimal je Sekunde aufgefrischt.

| Bedienelement | Wirkung |
| --- | --- |
| Filtern… | Engt den Baum auf die Zeilen ein, deren Name den Text enthält, ohne Rücksicht auf Groß- und Kleinschreibung. Ein Ordner überlebt, wenn irgendein Nachkomme passt, und klappt zu seinen Treffern auf; die Wurzel Assets engt sich auf die Kategorien ein, deren Name passt, oder kommt ganz, wenn nur ihr eigener Name passt; eine Wurzel des Adressraums, deren eigener Name passt, bleibt aufgeführt und lädt ihren Zweig beim Aufklappen, während die Abschnitte Actions und Triggers nur die passenden Zeilen aufführen. |
| Neu… (Fuß der Spalte) | Öffnet das Menü zum Anlegen: **Neue Variable**, **Neue Aktion**, **Neuer Auslöser**, **Neuer Alarm**, dann **Neuer Ordner** mit einem Ziel je Abschnitt (Variables, Alarms, Actions, Triggers). Alles, was hier entsteht, wird an der Wurzel seines Abschnitts unter dem ersten freien Namen der Reihen `Variable1`, `Action1`, `Trigger1`, `Alarm1` oder `Folder1` angelegt. Eine neue Definition wird nicht geöffnet (siehe [Anlegen und Kopieren](#creating-and-copying)); ein neuer Ordner öffnet sein Namensfeld in seiner Zeile im Baum. Nur für eine Rolle mit **Logic konfigurieren** gezeichnet; mit dem Grund ausgegraut, solange die Station gesperrt ist. |
| Alle ausklappen / Alle einklappen | Öffnet jeden Zweig (und lädt jede Ebene beim Öffnen) oder schließt alles zurück auf die Wurzeln. |
| Rechtsklick | An einer Wurzel eines Abschnitts, an einem Ihrer Ordner, an einer Zeile einer Definition oder an der Zeile Images, Icons, Colors oder Symbols: wählt die Zeile und öffnet ihr Menü (unten). An einem Knoten von einer anderen Seite öffnet sich nichts. |

Das Rechtsklickmenü trägt, je nach Zeile und Rolle: **Neue Variable / Neue Aktion / Neuer Auslöser / Neuer Alarm** (in den Ordner oder die Wurzel, die Sie angeklickt haben), **Neuer Ordner** (an einem Ordner, der schon drei Ebenen tief liegt, ausgegraut mit dem Grund), **Ausführen** (Aktionszeilen), **Quittieren** (Alarmzeilen), **Alle quittieren** (die Wurzel Alarms), **Aktivieren** oder **Deaktivieren** (Aktionen, Auslöser und Alarme), **Verschieben nach** (ein Untermenü mit der Wurzel des Abschnitts und jedem Ordner, in den die Zeile darf), **Kopieren**, das Löschen mit dem Namen der Leiste (**Variable löschen** und so weiter) und an einem Ordner **Ordner umbenennen** und **Ordner entfernen**. An Images, Icons, Colors und Symbols trägt es deren Leiste: **Bild importieren…**, **Neues eigenes Icon**, **Neue Farbe**, **Neues eigenes Symbol**, **Symbol importieren…** und **Chat-Anweisung kopieren**. Eine Rolle ohne Logic konfigurieren bekommt nur Ausführen, Quittieren und Alle quittieren, wenn sie Logic bedienen hat, und Chat-Anweisung kopieren an Symbols; eine Zeile ohne einen davon öffnet kein Menü.

Der Detailbereich ist leer, bis Sie etwas wählen: "Wählen Sie einen Knoten, um ihn anzusehen: Variablen, Aktionen, Auslöser und Alarme öffnen ihren Editor. Legen Sie einen mit Neu an."

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

Die Leiste zeichnet die Befehle des gewählten Knotens. Was die Rolle nie erlaubt, wird nicht gezeichnet; was die Situation gerade jetzt ablehnt, bleibt gezeichnet, ausgegraut, mit dem Grund in seinem Tooltip: "Die Projektierung ist gesperrt, solange eine Einheit läuft." während eines Vorgangs der Projektierung, "Runtime gestoppt", solange die Station nur lesend läuft.

| Auswahl | Führende Gruppe | Nachfolgende Gruppe (Gefahr) |
| --- | --- | --- |
| Einer Ihrer Ordner | Neue Variable / Aktion / Auslöser / Alarm (die Art, die sein Abschnitt hält), Neuer Ordner (an der Grenze der Tiefe ausgegraut mit "Dieser Ordner liegt bereits so tief, wie Ordner verschachtelt werden."), Ordner umbenennen | Ordner entfernen |
| Eine Variable | Kopieren | Variable löschen |
| Eine Aktion | Ausführen, Aktivieren oder Deaktivieren, Kopieren | Aktion löschen |
| Ein Auslöser | Aktivieren oder Deaktivieren, Kopieren | Auslöser löschen |
| Ein Alarm | Quittieren, Aktivieren oder Deaktivieren, Kopieren | Alarm löschen |
| Die Wurzel Alarms | Alle quittieren | |
| Assets, Images | Bild importieren… | |
| Assets, Icons | Neues eigenes Icon | |
| Assets, Colors | Neue Farbe | |
| Assets, Symbols | Neues eigenes Symbol, Symbol importieren…, Chat-Anweisung kopieren | |
| Ein Knoten unter System, Server, Connector oder Process | Der [Hinweis, dass anderswo bearbeitet wird](logic-from-other-pages#the-edited-elsewhere-notice), und seine Schaltfläche Öffnen | |

**Kopieren** verdoppelt die gewählte Definition an die Wurzel ihres Abschnitts, unter dem eigenen Namen der Quelle, wenn er frei ist, sonst als `Name (2)`, `Name (3)` und so fort, und markiert die Kopie in der Tabelle dieser Wurzel, statt sie zu öffnen (siehe [Anlegen und Kopieren](#creating-and-copying)); ein kopierter Alarm beginnt im Normalzustand, ein kopierter Auslöser beginnt ohne Zeitplan, eine kopierte Aktion hat keinen Lauf aufgezeichnet. **Aktivieren** und **Deaktivieren** legen das Kennzeichen Aktiviert der Definition über dasselbe automatische Speichern um wie jedes Feld. Jedes **Löschen** fragt zuerst ("'X' löschen? … Das lässt sich nicht rückgängig machen.") und meldet "Gelöscht." im Aktionsprotokoll; eine Variable oder einen Alarm zu löschen lässt jeden Ausdruck, jedes Skript, jede Bedingung und jede Verknüpfung im Dashboard, die seine Adresse genannt hat, unauflösbar zurück, was die [Validierung](validation) auflistet. Ein Löschen landet beim Elternknoten des Gelöschten: die Ansicht geht zu dem Ordner, in dem die Definition abgelegt war, oder zur Wurzel ihres Abschnitts, ausgewählt und im Baum geöffnet, mit seiner Tabelle dessen, was übrig ist, und **Ordner entfernen** landet ebenso beim Ordner darüber oder bei der Wurzel des Abschnitts.

## Anlegen und Kopieren {#creating-and-copying}

Anlegen öffnet nie, was es angelegt hat, und eine Kopie ist ein Anlegen. **Neue Variable**, **Neue Aktion**, **Neuer Auslöser** und **Neuer Alarm**, ob über das **Neu…** der Spalte, über das Rechtsklick-Menü einer Wurzel eines Abschnitts oder eines Ordners oder über die Befehlsleiste eines geöffneten Ordners, legen die Zeile unter dem ersten freien Namen ihrer Reihe an und bringen die Ansicht auf die Seite ihres Elternknotens: den Ordner, in dem sie abgelegt wurde, oder die Wurzel des Abschnitts. Der Baum wählt diesen Elternknoten aus und klappt ihn auf, die Tabelle auf der Seite markiert die neue Zeile und rollt sie in den sichtbaren Bereich, und das Aktionsprotokoll liest "Element 'Variable1' angelegt. Öffnen Sie es, um es zu bearbeiten." Ein Anlegen aus der Befehlsleiste des Ordners selbst lässt die Ansicht auf diesem Ordner. **Kopieren** tut dasselbe an der Wurzel seines Abschnitts, und das Aktionsprotokoll liest "Nach 'Setpoint (2)' kopiert. Öffnen Sie die Kopie, um sie zu bearbeiten." Ein im Feld **Filtern…** getippter Filter wird bei der Ankunft geleert, damit der Elternknoten und die neue Zeile im Baum stehen und ausgewählt und aufgeklappt gezeigt werden können.

Die Seite einer Wurzel eines Abschnitts oder eines Ihrer Ordner ist eine Tabelle dessen, was sie enthält, mit **Bezeichnung**, **Adresse** und **Wert** und am Ende jeder Zeile einem **Öffnen**, das die Definition genauso öffnet wie ihre Zeile im Baum (an der Wurzel Alarms findet eine Rolle mit **Logic bedienen** dort auch **Quittieren**). Eine Variable mit dem Ausgabetyp Icon, Bild oder Farbe zeichnet in ihrer Wertzelle ihr Icon, ihr Bild oder ihr Farbfeld, klein genug für die Zeile (eine Farbe zeigt zusätzlich ihren Hex-Wert); die Zelle schreibt den Quelltext des Icons nie aus. Ein Klick auf eine Zeile wählt sie, und die gewählte Zeile ist die markierte Zeile: Die Markierung bleibt, bis Sie eine andere Zeile wählen oder die Spalte anderswohin führen. Ein neuer Ordner ist die Ausnahme: Er öffnet sein Namensfeld in seiner Zeile im Baum.

## Ordner {#folders}

Jeder der vier Abschnitte lässt sich in Ordner gliedern. Ein Ordner gehört zu einem Abschnitt und hält nur Einträge dieses Abschnitts; er schachtelt sich höchstens drei Ebenen tief. Ein Ordner ist reine Gliederung: Er hat keine Berechtigung, keine Auswertung und keinen Zustand.

Für **Variables** und **Alarms** bildet die Kette der Ordner die Adresse: Eine Variable in `Forno` liest `Variables.Forno.Setpoint`, eine in seinem Unterordner `Zona1` liest `Variables.Forno.Zona1.Setpoint`. Eine Ebene eines Abschnitts ist ein einziger Namensraum aus Segmenten, den seine Ordner und seine Definitionen teilen: Zwei Ordner dürfen je einen `Setpoint` halten, aber nichts, was auf derselben Ebene liegt, darf auf dasselbe Segment führen, und der Editor lehnt einen solchen Namen schon beim Tippen ab und nennt die bereits vergebene Adresse. **Actions** und **Triggers** werden über ihre Identität angesprochen, ihre Ordner gliedern also nur den Baum, und ihre Bereiche zeigen statt einer Adresse eine Zeile mit dem Ort.

| Befehl | Was geschieht |
| --- | --- |
| Neuer Ordner | Legt einen leeren Ordner namens `FolderN` an und öffnet sein Namensfeld in der Zeile des Baums; das Feld leer oder unverändert zu verlassen behält diesen Namen. |
| Ordner umbenennen | Öffnet das Namensfeld in der Zeile. Jede Adresse unter dem Ordner zieht mit, jeder Verweis wird umgeschrieben, und das Aktionsprotokoll sagt, wie viele ("Ordner umbenannt; 3 Verweise aktualisiert."). |
| Verschieben nach | Legt einen Ordner oder eine Definition unter einen anderen Ordner desselben Abschnitts oder zurück an die Wurzel des Abschnitts; Adressen und Verweise folgen. Die Liste bietet nur die erlaubten Ziele an: nie den Ordner selbst, nie einen seiner eigenen Unterordner, nie einen anderen Abschnitt und nie eine Ebene, auf der seine Unterordner die Grenze der Tiefe überschreiten würden. |
| Ordner entfernen | Fragt zuerst und sagt, was sich bewegt: "Seine 3 Einträge gehen nach Variables; nichts wird gelöscht. Verweise auf die Adressen, die sich bewegen, werden aktualisiert." Die Einträge und Unterordner rücken eine Ebene nach oben; das Entfernen wird abgelehnt, wenn zwei von ihnen am Ziel zusammenstoßen würden. |

## Der Zyklus und die Warteschlange {#the-sweep-and-the-queue}

Die Runtime läuft auf zwei Spuren, und keine von beiden wartet je auf die Anlage. Der **Zyklus** läuft alle 100 ms auf einer einzigen, der Reihe nach abgearbeiteten Warteschlange: Er wertet jede Variable vom Typ Expression aus, dann jede aktivierte Alarmbedingung, in dieser Reihenfolge, eine Bedingung liest also die Werte der Variablen aus diesem Zyklus, und er trägt außerdem die von anderswo eintreffenden Schreibvorgänge auf Merker und Tags sowie die Quittierungen der Alarme. Die **Aktionsspur** führt die Aktionsskripte aus, eines nach dem anderen, in der Reihenfolge, in der sie angefordert wurden. Ein eigener Durchlauf, ebenfalls alle 100 ms, wirft fällige [Auslöser](logic-triggers) auf die Aktionsspur.

Weil die Spuren voneinander unabhängig sind, kann ein Zyklus mitten in einem Skript stattfinden, zwei Lesevorgänge in einem Skript können also verschiedene Durchgänge sehen; dafür hält ein Skript, das auf ein Gerät wartet, allein die Aktionen hinter sich auf, nie die Ausdrücke, die Alarme oder den Bediener. Die Schreibvorgänge geraten darüber nicht durcheinander: Die Reihenfolge wird dort gewahrt, wo die Leitung ist, eine Warteschlange je Gerät (siehe unten). Die Verbraucher (Dashboards, Kanäle, diese Seite) lesen den veröffentlichten Zustand; nichts auf dieser Seite stößt eine Auswertung von Hand an.

## Werte schreiben {#writing-values}

Jeder Schreibvorgang geht durch einen Kanal, gleich, was ihn ausgelöst hat: die Zuweisung eines Skripts oder `Write(...)`, das Feld **Wert setzen** einer Variablen der Art Merker, ein Bedienelement im Dashboard, ein Rezept von Process, der Agent, ein externer OPC UA-Client, der einen öffentlichen Knoten schreibt, ein Modbus-Client, der eine Zeile der Tabelle des [Modbus-Servers](connector-modbus-server) schreibt, die Schreiben erlaubt. Der Kanal lehnt einen Wert ab, der nicht endlich ist oder sich nicht in den Typ des Ziels wandeln lässt, lehnt eine Quelle ab, die ein laufendes Rezept oder eine Verriegelung hält (und nennt den Halter), protokolliert den Schreibvorgang als alten Wert auf neuen Wert unter seiner Quelle (Bediener, MCP, der Lauf) und wendet ihn an. Was der Kanal entscheidet, entscheidet er, ohne irgendwo nachzufragen: den Wert, das Ziel, die Sperre und ob das Gerät überhaupt verbunden ist. Ein Schreibvorgang auf ein Tag, den er durchlässt, wird danach der eigenen Auslieferungswarteschlange dieses Geräts im Connector übergeben, in der die diesem Gerät geschuldeten Werte einer nach dem anderen gesendet werden, in der Reihenfolge ihres Eintreffens, während die anderen Geräte nebenher bedient werden; ein Wert, den dort ein neuerer Schreibvorgang auf dasselbe Tag überholt, verlässt die Warteschlange nie, und der neuere ist der, den die Anlage erfährt. Wer gefragt hat, ist auch, wer auf die Antwort wartet, außerhalb der Logic und in seinem eigenen Code: die Komponente des Dashboards, das Schreiben von Hand auf der [Seite des Tags](connector-tags#the-live-value-card), das Werkzeug des Agenten, der externe OPC UA-Client, der Modbus-Client, ein laufendes Rezept, und ein Skript nur dort, wo es `WriteAndWait` gesagt hat. Ein Schreibvorgang, dessen Quelle eine Aktion ist, ist die Ausnahme: Er geht allein in die [ausführliche Aufzeichnung](events-console#detailed-capture) und nie in die Konsole der Ereignisse, denn ein Skript, das in jedem Zyklus schreibt, erzeugt Werte zu Tausenden und würde die Neuigkeiten der Station darunter begraben. Was die Konsole von einer Aktion trägt, sind ihre Fehlschläge. Ein Schreibvorgang auf ein Tag nimmt den technischen Wert und durchläuft die [Wertkette](connector-value-pipeline) des Tags rückwärts bis zu dem Rohwert, den das Gerät nimmt. Die Einzelheiten stehen auf [Variablen](logic-variables#set-value) und [Aktionen](logic-actions#what-an-action-may-write).

## Berechtigungen und Sperren {#permissions-and-locks}

| Berechtigung | Was sie hier erlaubt |
| --- | --- |
| Logic anzeigen | Die Seite zu öffnen und alles darauf zu lesen, die laufenden Werte eingeschlossen. |
| Logic konfigurieren | Variablen, Aktionen, Auslöser, Alarme und Ordner anzulegen, zu bearbeiten, umzubenennen, zu verschieben, zu kopieren, zu aktivieren, zu deaktivieren und zu löschen und die Bibliothek der Ressourcen zu pflegen. |
| Logic bedienen | Einen Wert eines Merkers zu schreiben, eine Aktion auszuführen, Alarme zu quittieren, hier, auf Dashboards und auf der Seite Ereignisse. |

Eine Rolle mit allein Logic anzeigen liest die ganze Seite: Die Editoren sind unter einem Hinweis inaktiv ("Ihre Rolle darf Logic anzeigen, aber nicht konfigurieren (Variablen, Aktionen, Auslöser, Alarme und Ressourcen).") und kein Befehl zum Konfigurieren oder Bedienen wird gezeichnet. Eine Rolle mit Bedienen, aber ohne Konfigurieren behält Ausführen, Quittieren, Alle quittieren und Wert setzen aktiv. Solange eine Einheit von Process die Station hält, zeigt die Seite den Hinweis auf die Projektierungssperre, und jeder Befehl und jedes Feld zum Konfigurieren ist ausgegraut; Ausführen, Quittieren und Wert setzen bleiben verfügbar. Solange die Runtime gestoppt ist, lehnen sowohl Konfigurieren als auch Bedienen mit "Runtime gestoppt" ab; Baum und Bereiche bleiben lesbar, tragen aber keine laufenden Daten. Der Katalog der Bits steht auf [Berechtigungen](users-permissions).

## Was die Seite nicht tut {#what-the-page-does-not-do}

Es gibt kein Speichern und kein Rückgängig: Ein Tastendruck ist eine gespeicherte Änderung (das Aktionsprotokoll sagt "Gespeichert."), und ein abgelehntes Speichern lädt das Feld auf das zurück, was die Station hält. Definitionen, die der Agent über seine eigenen Werkzeuge anlegt, ändert oder löscht oder die ein anderes Fenster ändert, erscheinen von selbst in der offenen Spalte. Ein Editor, der eine so gelöschte Definition offen hat, schließt sich, und das Aktionsprotokoll nennt sie und sagt, dass sie außerhalb des Editors gelöscht wurde. Die Historie der Alarme, die Konsole der Ereignisse und die Dashboards wohnen auf ihren eigenen Seiten.
