====================================================================== PLC Datenlogger – User Manual ====================================================================== .. contents:: Contents :depth: 2 :local: Overview ====================================================================== The PLC Datenlogger (PLC data logger) cyclically reads variables from one or **several** controllers **of different manufacturers at the same time**, stores all measurements in a common CSV file (and/or a database) and displays them as a y-t chart – in the user interface, in the browser (web server) or not at all (headless operation, recording only). It replaces the former single programs *S7 Datenlogger*, *TIA Datenlogger* and *CLX Datenlogger*. Communication with the controllers is handled by **drivers**; each controller in the configuration gets its own driver. Built in are: .. list-table:: :header-rows: 1 :widths: 12 38 50 * - Driver - Controllers / protocol - Library, addressing * - ``s7`` - Siemens S7-300/400/1200/1500 via S7 communication (PUT/GET) - python-snap7; absolute addresses such as ``DB10.DBD4``, ``M5.0``, ``EW64`` * - ``tia`` - Siemens S7-1200/1500 symbolically via S7CommPlus (like TIA Portal/HMI), including optimized blocks, without PUT/GET - s7commplus; symbolic names such as ``Anlage_DB.Motor[2].Drehzahl`` * - ``clx`` - Allen-Bradley ControlLogix, CompactLogix, Micro800 via EtherNet/IP (CIP) - libplctag (+ pycomm3 for the tag list); tag names such as ``Program:Main.Druck`` * - ``modbus`` - Modbus TCP (Wago, Schneider, Beckhoff, Phoenix Contact, drives, energy meters, gateways …) - no additional library; ``40001``, ``30001``, ``00001``, ``10001`` or ``HR0``, ``IR0``, ``C0``, ``DI0`` * - ``modbus_rtu`` - Modbus RTU via RS-485/RS-232 (several devices on one port) - pymodbus, pyserial; addresses as for ``modbus`` * - ``opcua`` - OPC UA: Beckhoff, B&R, Codesys, Siemens, Omron, Rockwell (gateway), Kepware … – controllers of many manufacturers - asyncua; NodeId such as ``ns=4;s=MAIN.fTemperatur``; selection from the server * - ``slmp`` - Mitsubishi MELSEC iQ-R, iQ-F, Q, L (SLMP/MC protocol, Ethernet) - no additional library; ``D100``, ``M10``, ``X1F``, ``ZR1000`` * - ``kvhostlink`` - KEYENCE KV-8000/7000/5000/3000/Nano, KV-X (Host Link, Ethernet) - no additional library; ``DM100``, ``R1000``, ``EM0``, ``T10`` * - ``toyopuc`` - JTEKT TOYOPUC PC10G/PC10, PC3J, Nano 10GX (Computer Link, Ethernet) - no additional library; ``D0100``, ``M0010``, ``P1-D0100`` (hex) * - ``s5as511`` - Siemens S5 via the PG interface (AS511, serial, 20 mA adapter) - pyserial; ``DB10.DW4``, ``EW0``, ``MW10``, ``T5`` * - ``logo`` - Siemens LOGO! 0BA7 and 0BA8 (LOGO! 8, 8.FS4, 8.3, 8.4) - python-snap7; ``VW10``, ``V2.3``, ``I1``, ``Q2``, ``M5``, ``AI1``, ``AM3`` * - ``pccc`` - Allen-Bradley MicroLogix 1100/1400, SLC 5/05 (EtherNet/IP, PCCC) - pycomm3; ``N7:0``, ``F8:2``, ``B3:0/5``, ``T4:0.ACC`` * - ``ads`` - Beckhoff TwinCAT 2/3 via ADS (AMS/TCP) - no additional library; ``MAIN.fTemperatur``, ``GVL.aWerte[3]``, ``%MW10``; selection from the symbol table * - ``fins`` - Omron CJ, CS, CP, NJ/NX via FINS/TCP or FINS/UDP - no additional library; ``D100``, ``W10``, ``CIO0.05``, ``E0_100`` Further drivers can be added **without changing the program**: a Python file in the ``treiber`` folder of the data folder is enough (see `Developing drivers `__). The program consists of several files. The program files (``plc_*.py`` and the package ``plc_treiber/``) are in the ``src`` folder, the manual with its images in the ``doc`` folder; language files, icon, logo, ``plctag.dll`` and the build files are in the project folder above. When started from source, the project folder is also the data folder (configuration, recordings, log file). .. list-table:: :header-rows: 1 :widths: 25 75 * - File - Purpose * - ``plc_config.py`` - Configuration program: define project, controllers and drivers, charts, Y axes and variables. Saves to a JSON file with any name (default ``plc_config.json``). * - ``plc_logger.py`` - Start program of the logger: chooses the operating mode (user interface or headless) from the configuration or the command-line parameters. * - ``plc_gui.py`` - User interface of the logger: charts, online/offline mode, rulers, status LEDs. Loaded by ``plc_logger.py``. * - ``plc_headless.py`` - Operation without user interface (recording only, no Qt needed). * - ``plc_recorder.py`` - Recording core without user interface: one read thread per controller (with the reader of its driver), one collector thread for merging, formulas, data buffer, CSV and archive. * - ``plc_treiber/`` - The drivers: ``base.py`` (interface), ``__init__.py`` (directory, loads built-in and own drivers), ``ui.py`` (connection settings dialog), ``s7.py``/``s7_symbols.py``/``s7_browser.py``, ``tia.py``/``tia_io.py``/``tia_taglist.py``/``tia_browser.py``, ``clx.py``/``plc_io.py``/``plc_taglist.py``/``plc_browser.py``, ``modbus.py``, ``modbus_rtu.py``, ``opcua.py``/``opcua_browser.py``, ``slmp.py``, ``kvhostlink.py``, ``toyopuc.py``, ``fins.py`` (common basis ``word_common.py``), ``s5as511.py``, ``logo.py``, ``pccc.py``, ``ads.py``/``ads_browser.py``, ``ringbuffer.py`` (ring buffers for cycle-synchronous recording) and ``_vorlage.py`` (template for own drivers). * - ``plc_web.py``, ``plc_webauth.py``, ``plc_web_dialog.py`` - Web server (Flask) with a Chart.js page for viewing the charts in the browser; HTTPS, users and passwords, user management in the configuration program. * - ``plc_report.py`` - PDF reports (statistics, trend, events) per shift/day/week/month or manually. * - ``plc_analysis.py``, ``plc_analysis_dialog.py`` - XY chart and frequency analysis (FFT) in the logger. * - ``plc_csvjoin.py`` - Reading and joining recordings (CSV/ZIP). * - ``plc_svg.py`` - SVG export of a chart (independent of Qt). * - ``plc_util.py`` - Small helper functions (formatting, axis ticks, data reduction). * - ``plc_db.py`` - Recording to SQLite, MariaDB, TimescaleDB/PostgreSQL, QuestDB, InfluxDB 3, VictoriaMetrics or Prometheus (own writer thread). * - ``plc_db_dialog.py`` - Read mode: choose a time range from the database and show it in the logger. * - ``plc_cleanup.py`` - Clean-up of old recordings (CSV/archive) by period or storage space. * - ``plc_netscan.py``, ``plc_netscan_dialog.py`` - Scanning the network for reachable controllers (configuration program). * - ``plc_iocheck_start.py`` - Start program of the IO check as a program of its own (``PLCIOCheck.exe``). * - ``plc_events.py`` - Triggers and event log (evaluation, file, acknowledgement). * - ``plc_event_viewer.py`` - Event viewer (display and acknowledge); can also be started on its own. * - ``plc_trigger_dialog.py`` - Trigger editor of the configuration program. * - ``plc_pid.py`` - PID controller tuning: process model, tuning rules, simulation (without user interface). * - ``plc_pid_dialog.py`` - PID tuning window (logger) and its settings (configuration program). * - ``plc_i18n.py``, ``sprachen/`` - Language switching and language files (``de.txt`` = template, ``en.txt`` = English). * - ``plc_splash.py`` - Start screen (choice of configuration, loading indicator). * - ``build_appimage.sh``, ``build_macos.sh``, ``tools/extract_tr.py`` - Build the Linux AppImage and .deb package or the macOS app; update the language files after program changes. * - ``plc_common.py`` - Data model and configuration file (JSON) (including import of the configurations of the single programs). Not started directly. * - ``build.bat``, ``installer.iss``, ``tools/make_icon.py``, ``requirements.txt`` - Building the Windows installer (see `Building the installer (Windows) `__). * - ``app.ico``, ``logo.png`` - Program icon (default if nothing is entered in the configuration; also used for the ``.exe`` files and the installer) and manufacturer logo (start screen, “About …”). * - ``icons/``, ``tools/make_program_icons.py`` - Icons of the individual programs (logger, configuration, IO check, event log, headless) as ``.ico`` and ``.png``; the script redraws them (needs Pillow). * - ``doc/`` - User manual (German ``bedienungsanleitung.rst``, English ``user_manual.rst``) and its images (``doc/images/``). * - ``plctag.dll`` - libplctag for Windows (64 bit), required by the ``clx`` driver. * - ``plc_block_dialog.py`` - Editor for blocks (block read mode), opened by the configuration program. * - ``plc_formula.py`` - Evaluation of the formulas of calculated variables. Not started directly. * - ``plc_formula_dialog.py`` - Editor for calculated variables (opened by the configuration program). * - ``plc_branding.py`` - Program icon and logo. Not started directly. Features: * **Controllers of different manufacturers in one recording**, e.g. an S7-1500 (symbolic), an S7-300 (PUT/GET), a ControlLogix and a Modbus energy meter – with a common time axis, common charts and formulas across controllers * **Extensible** with own drivers (put a Python file into a folder, done) * One read thread per controller with its own sampling interval; a slow or failed controller does not slow down the others * **Status LEDs** for every connection (grey, yellow, green, red) * Selection of variables directly from the controller (TIA: variable list of the CPU, CLX: tag list) or from exported DB sources (S7) * Block read mode: read many values with one request (array sections, contiguous address ranges) * Configurations of the single programs (S7, TIA, CLX) are imported; older INI files are converted once * Project name and configuration files with any name (open dialog) * **Web server** for viewing the charts in the browser (tablet, smartphone) * **Headless operation** (without charts, recording only) * CSV log with millisecond timestamps, file size limit with automatic ZIP archiving (name/year/month/day), database recording with read mode (choose a time range from the database and display it) * Calculated variables from formulas (e.g. mean, difference, integral) * Triggers and event log with acknowledgement and own notes; trigger marks on the time axis of the charts * **Recording by trigger** with ring buffer: adjustable pre- and post-trigger time, each capture in its own CSV file * PID controller tuning from recorded step responses * **XY chart** and **frequency analysis (FFT)** * **PDF reports** per shift, day, week or month (automatic) or for a time range * Join CSV files and save them as a new file * Web server optionally with **HTTPS and login** * Several charts, several Y axes per chart; pages/tabs, grid layout * Legend with live values, online/offline mode with rulers, bars for current values * Screenshots of single charts as PNG or SVG * Language switching (German, English, own language files) * Demo mode with simulated values (without a PLC) Installation and start ====================================================================== Requirements ---------------------------------------------------------------------- * Python 3.9 or newer (64 bit) * Install the libraries (all at once): .. code-block:: console pip install -r requirements.txt or individually: .. code-block:: console pip install PySide6-Essentials pyqtgraph numpy Flask # user interface, web server pip install python-snap7 # drivers s7 and logo pip install s7commplus # driver tia pip install pycomm3 # driver clx (tag list), driver pccc pip install pymodbus pyserial # driver modbus_rtu pip install asyncua # driver opcua pip install pyserial # driver s5as511 pip install cryptography # web server with HTTPS Only the libraries of the drivers you actually use are needed. If one is missing, the driver is still listed; the controller's settings dialog and **Driver › Installed drivers …** then show “✗ library missing”. The drivers ``modbus``, ``slmp``, ``kvhostlink``, ``toyopuc``, ``fins`` and ``ads`` need no library. Headless operation needs neither PySide6 nor pyqtgraph. * **libplctag** (only driver ``clx``) is not a pip package. ``plctag.dll`` (Windows, 64 bit) is required; it is supplied with the program. Otherwise download the package ``libplctag__windows_x64.zip`` from https://github.com/libplctag/libplctag/releases and put ``plctag.dll`` **next to the program files**, or specify its path in the environment variable ``CLX_PLCTAG_LIB``. On Linux ``libplctag.so`` is used. libplctag is licensed under MPL 2.0 or LGPL 2; observe the license notes when redistributing. Starting the programs ---------------------------------------------------------------------- .. code-block:: console python src/plc_config.py [file.json] # configuration python src/plc_logger.py [file.json] # logger (user interface or headless) Without a file name, the **last used** configuration file is opened (default: ``plc_config.json``). The file name is arbitrary. Further logger parameters: .. list-table:: :header-rows: 1 :widths: 30 70 * - Parameter - Effect * - ``file.json`` or ``--config file.json`` - Configuration file to use (and to open again at the next start without a file name). * - ``--headless`` - Start without user interface, record only (overrides the configuration). * - ``--gui`` - Open the user interface even if the configuration asks for *headless*. * - ``--demo`` - Simulated values instead of a PLC connection (see `Demo mode `__). * - ``--iocheck`` - Open only the `IO check `__ (commissioning: check the signal list). The logger can open the configuration program itself (**Config editor** in the toolbar), and the configuration program can start the logger or the IO check (**File › Start logger with this configuration**, **File › Start IO check with this configuration**). The IO check also has a start program of its own: ``python src/plc_iocheck_start.py`` (installed: ``PLCIOCheck.exe``). Every program has an icon of its own: the “Ti” of the logo with a coloured badge. This way logger, configuration, IO check, event log and headless operation can be told apart in the taskbar, start menu and dock. A custom icon entered in the configuration (tab *Display*) applies to the logger and the event log. .. figure:: images/en/programm_icons.png :alt: Icons of the programs :width: 90% :align: center Icons of the programs (large and in taskbar sizes). Preparing the controllers ---------------------------------------------------------------------- The logger only reads; it never writes to the controllers. What has to be set up in the controllers depends on the driver and is described for each driver in the chapter `Controllers and drivers `__. In short: * ``s7``: on S7-1200/1500 *permit access with PUT/GET communication from remote partner* and read only **non-optimized** data blocks. TCP port 102. * ``tia``: nothing to set up; possibly the access-level password and TLS. TCP port 102. * ``clx``: *External Access* of the tags *Read/Write* or *Read Only*. TCP port 44818. * ``modbus``: Modbus TCP enabled in the device, registers as per device manual. TCP port 502. * ``modbus_rtu``: device address, baud rate and parity as per device; bus terminated (120 Ω at both ends). * ``opcua``: OPC UA server of the controller enabled, variables released; with security, trust the client certificate in the server. Usually TCP port 4840. * ``ads``: route to this computer in TwinCAT. TCP port 48898. * ``slmp``: in GX Works create an SLMP/MC protocol connection (binary) with a port. * ``fins``: FINS enabled on the Ethernet unit. Port 9600. * ``logo``: server connection (S7) / HMI access in LOGO!Soft. TCP port 102. * ``pccc``: nothing to set up. TCP port 44818. * ``kvhostlink``: nothing to set up. TCP port 8501. * ``toyopuc``: set up a Computer Link port in PCwin. * ``s5as511``: PG adapter (20 mA) on the PG interface; do not connect STEP 5 at the same time. The PC firewall must allow the connections on the ports mentioned. .. _startbild: Start screen ---------------------------------------------------------------------- When the logger and the configuration program start, the **start screen** appears: .. figure:: images/en/startbild.png :alt: Start screen :width: 80% :align: center Start screen of the configuration program: choose or create a configuration. * **Recently used**: the configurations opened last, with folder and modification date. Double-click or **Open** (Enter key) starts with the selected file. * **Browse …**: choose any configuration file. * **New configuration …**: in the logger you are asked for a file name, an empty configuration is created and the configuration program is opened as well; in the configuration program a new, not yet saved configuration begins. * **Demo** (logger only): start with simulated values. * **Do not show at startup**: in future start immediately with the last used file. To switch it on again: in the logger **File → Show start screen at program start**. After the choice, the start screen shows the loading progress until the main window is ready. If a configuration file is passed on the command line (e.g. ``PLCLogger.exe plant.json``), there is no choice. The window can be moved with the mouse; **Esc** or ✕ quits. Quick start ====================================================================== #. Start ``plc_config.py``. #. In the tab *Project & controllers* enter a project name and the controller(s): **Name**, choose the **Driver**, set up the connection with **…** (IP address and the parameters of the driver), interval. #. Take variables from the controller with the selection button of the driver (e.g. **Select from variable list…**, **Select from tag list…**, **Select from DB source…**), or enter the address by hand with **Add variable**. #. Check with **Test connection** that the values are read correctly. #. **Save** (or **Save as…** with a file name of your own) and close the configuration program. #. Start ``plc_logger.py`` and press **▶ Start**. .. tip:: An existing configuration of the S7, TIA or CLX data logger is simply opened with **File › Open…** (see `Importing configurations of the single programs `__). Without a PLC you can try the program in **Demo** mode (see `Demo mode `__). Configuration program (``plc_config.py``) ====================================================================== .. figure:: images/en/config_gesamt.png :alt: Configuration program :width: 90% :align: center The configuration program: tabs at the top, assignment tree on the left, variable table on the right. Project, controllers and settings ---------------------------------------------------------------------- The upper part of the window is divided into several tabs. **Tab “Project & controllers”** .. figure:: images/en/config_projekt_steuerungen.png :alt: Tab Project and controllers :width: 80% :align: center Tab “Project & controllers”. .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Meaning * - Project name - Freely chosen name of the project. It appears in the window titles, in the web server and in the log. * - Controllers (table) - One row per controller with the columns: * **Name** – unique, also used for the status LED. * **Driver** – choice of all loaded drivers (``s7``, ``tia``, ``logo``, ``clx``, ``pccc``, ``modbus``, ``opcua``, ``ads``, ``fins`` … and own ones). When the driver is changed, the connection parameters are set to its defaults; the IP address is kept. The type lists of this controller's variables adapt. * **Connection** – short description of the connection, e.g. ``192.168.0.1, Rack 0/Slot 1`` or ``192.168.0.10:502, Unit 1``. * **…** – opens the connection's **settings dialog** (see below). Double-clicking *Connection* has the same effect. * **Interval** – time between two measurements of this controller, 10 to 60000 ms. * **Active** – disabled controllers are not read. Change the list with **+ Controller** and **Remove controller**; when a controller is removed, its variables and blocks move to the first controller. **Scan network …** finds reachable controllers: in the *range* (suggestion: the own network, e.g. ``192.168.0.0/24``; also ``192.168.0.10-50`` or single addresses, separated by commas) the scan asks for EtherNet/IP devices by broadcast and tries connections on the ports of S7 (102), Modbus (502), EtherNet/IP (44818), OPC UA (4840), ADS (48898), FINS (9600), SLMP (5007) and Keyence (8501). With *Read device identity* it shows module, order number, station and slot of S7 CPUs, and product name, vendor and serial number of EtherNet/IP devices. Each hit gets a driver suggestion (S7-1200/1500: ``tia``, other S7: ``s7`` with the slot found, Logix: ``clx``, OPC UA with endpoint, ADS with AMS Net ID *IP*.1.1 …); **Add as controller** adds the ticked hits with their address. Addresses already configured are marked and not preselected. Devices behind routers are only found if their range is given; a firewall can block ports. .. figure:: images/en/netzwerksuche.png :alt: Scan network :width: 95% :align: center Scan network: controllers found with identity and driver suggestion; the address already configured is not preselected. **Connection settings dialog.** The dialog is built from the driver's parameters (text fields, numbers, choice lists, password fields). Rarely needed parameters are in the *Advanced* section. At the bottom the dialog shows whether the required library is installed (✓ or ✗ with error message). On **OK** the driver checks the input (e.g. an empty IP address). The parameters of the built-in drivers are described in the chapter `Controllers and drivers `__. In the logger, each controller is read by **its own thread**. The interval applies per controller; a slow or failed controller does not slow down the others. The measurements of all controllers – whatever their driver – are merged into one common CSV file (one column per variable). **Menu “Driver”** * **Installed drivers …** – overview of all loaded drivers with ID, name, required library and its state; below, drivers that could not be loaded (with error message), and the folder for own drivers. * **Open folder for own drivers …** – creates the folder ``treiber`` in the data folder (if necessary), copies the template ``_vorlage.py`` into it and opens it in the file manager (see `Developing drivers `__). **Tab “Recording”** .. figure:: images/en/config_aufzeichnung.png :alt: Tab Recording :width: 80% :align: center Tab “Recording”. .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Meaning * - Write CSV file - Switches the CSV file on or off (e.g. off if recording only to a database; see `Database recording `__). * - CSV folder - Target folder for the log files. A relative path refers to the program folder. * - CSV name - Name of the recording. It is the prefix of the file names and the name of the archive subfolder (default: ``log``). The characters ``\ / : * ? " < > |`` are not allowed. * - Max. records per file - Upper limit for the number of records (rows) per CSV file. ``0`` = unlimited. When the number is reached, the file is zipped and archived (see `Limiting the file size and archiving `__). * - Archive folder - Base folder of the archive (default: ``archiv``). A relative path refers to the program folder. * - Archive when closing - If ticked (default), the current, not yet full CSV file is also zipped and archived when the logger is closed. * - Delete after, Use at most - Clean-up of old recordings of this logger (CSV files and archive ZIPs): files whose last change is more than *n days* ago are deleted; if all together take up more than *n MB*, the oldest are deleted until the limit is met. *never*/ *unlimited* (0) = off. See `Cleaning up old recordings `__. * - Recording - *Continuous* (default) or *By trigger with pre- and post-trigger time*: then data is only saved while the start condition is met (see `Recording by trigger (pre- and post-trigger) `__). * - Start condition - Condition as for triggers, e.g. ``{Druck} > 5 or {Störung} == 1``; **…** opens the formula editor. * - Pre-trigger, post-trigger, max. - Seconds before the trigger (ring buffer), after the end of the condition, and the maximum duration of a capture (*unlimited* = 0). **Tab “Display”** .. figure:: images/en/config_anzeige.png :alt: Tab Display :width: 80% :align: center Tab “Display”. .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Meaning * - Display window (online) - Width of the visible time window in online mode, in seconds. * - Default page layout - Layout at start: *Stacked*, *Side by side* or *Tabs*. * - Charts on one page - *Automatic* (like the default layout), *Stacked*, *Side by side* or *Grid*. * - Grid columns - Number of columns for *Grid*; *automatic* derives it from the number of charts. * - Show bars for current values - Switches the narrow bars next to the charts on by default. * - Bar width - Width of a bar in pixels (4 … 40, default 14). * - Logo - Image file, e.g. the company logo. It appears in the logger at the top right of the menu bar (28 pixels high), on the web pages (charts, process view, login) and in the header of PDF reports and IO check protocols. PNG and JPG work everywhere, SVG only in the logger and on the web pages. A relative path refers to the program folder. **Empty = supplied manufacturer logo** (``logo.png``), **“-” = no logo.** * - Customer logo - Second logo (e.g. of the customer or plant), shown in the same places to the left of the logo, in the PDF at the top left. Empty = no customer logo. * - Program icon - Icon for windows and taskbar of the logger and the event log (PNG, ICO or SVG). Without an entry the program's own icon is used (folder ``icons``, otherwise ``app.ico``). The configuration program and the IO check keep their own icons. **Tab “Database”** .. figure:: images/en/config_datenbank.png :alt: Tab Database :width: 80% :align: center Tab “Database”. Choice and access data of a database that is recorded to in addition to or instead of the CSV file (SQLite, MariaDB/MySQL, TimescaleDB/PostgreSQL, QuestDB, InfluxDB 3, VictoriaMetrics, Prometheus), with the button **Test database**. Details in the chapter `Database recording `__. **Tab “Triggers & events”** .. figure:: images/en/config_trigger_ereignis.png :alt: Tab Triggers and events :width: 80% :align: center Tab “Triggers & events”. Shows the number of triggers defined. **Edit triggers …** opens the trigger editor, **Show event log …** the event viewer, and *Event file* sets where the event log is stored (empty = next to the CSV file). Details in the chapter `Triggers and event log `__. **Tab “Reports (PDF)”** .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Meaning * - Create PDF report automatically - At the end of each period the logger writes a report (also in headless operation); a partial report is created when stopping. * - Period - *Shift*, *Day*, *Week* (from Monday) or *Month*. * - Shift starts - Times separated by commas, e.g. ``06:00,14:00,22:00``. * - Day start - Time at which day, week and month begin (e.g. ``06:00`` for a production day). * - Folder - Target folder (default ``berichte`` in the data folder). Details in the chapter `PDF reports `__. **Tab “Web server & headless”** .. figure:: images/en/config_web_headless.png :alt: Tab Web server and headless :width: 80% :align: center Tab “Web server & headless”. .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Meaning * - Start web server - Starts a web server together with the logger (see `Web server (charts in the browser) `__). * - Address (host) / port - ``0.0.0.0`` makes the server reachable in the whole network, ``127.0.0.1`` only on the computer itself. Default port: 8080. * - Access code - Optional. If a code is set, it must be given when opening the page with ``?token=CODE``. * - Browser refresh - How often the browser page fetches new data (200 to 60000 ms). * - Headless mode - The logger starts without user interface and only records (see `Headless operation (recording only) `__). * - Headless loggers - **Running loggers …** shows the running headless loggers and stops them cleanly on request; next to it is the number of running loggers. * - HTTPS (encrypted) - Encrypted connection. Without a certificate of your own, the program creates a self-signed one once (folder ``web_tls``). * - Certificate / key (PEM) - Optionally your own certificate and key (e.g. from the company CA). * - Login - **Users …** creates users with password (only a hash is stored). Without users no login is needed. See `HTTPS and login `__. Structure: charts, Y axes and variables ---------------------------------------------------------------------- The display is structured hierarchically: .. code-block:: text Chart ├── Y axis 1 (left) │ ├── Variable A │ └── Variable B └── Y axis 2 (right) └── Variable C * Each **chart** appears in the logger as its own movable window. * Each chart has at least one **Y axis**. The first axis is on the left, all others on the right. Each axis scales independently. * Each **variable** belongs to exactly one Y axis of one chart. The tree on the left shows this structure. Below it are the buttons: .. list-table:: :header-rows: 1 :widths: 25 75 * - Button - Effect * - **+ Chart** - Creates a new chart with one Y axis. * - **+ Y axis** - Adds another Y axis to the selected chart (or the chart of the selection). * - **Remove** - Removes the selected chart, Y axis or variable. Affected variables move to the first axis or the first chart. The last chart and the last axis of a chart cannot be removed. Properties of chart and Y axis ---------------------------------------------------------------------- .. figure:: images/en/config_eigenschaften.png :alt: Properties of chart and Y axis :width: 90% :align: center Properties of the selected chart or Y axis. Select a chart or a Y axis in the tree. In the *Properties* area below you can change: .. list-table:: :header-rows: 1 :widths: 25 75 * - Field - Meaning * - Name - Name of the chart or Y axis (shown as title or axis label). * - Page (tab) - *Charts only.* Charts with the same page name are shown together on one page (tab or dock), e.g. ``Process`` or ``Alarms``. Empty = default page (see `Pages, charts and layout `__). * - Controller - *Charts only.* Tick **PID controller tuning** and **Settings …**: define setpoint, process value and controller output for calculating the controller parameters in the logger (see `PID controller tuning `__). * - Auto scaling - *Y axes only.* Active: the axis adapts automatically to the visible data. Inactive: the fixed limits *Y min* and *Y max* apply. * - Y min / Y max - Fixed axis limits. *Y max* must be greater than *Y min*. Creating variables ---------------------------------------------------------------------- .. figure:: images/en/config_variablen.png :alt: Variable table :width: 90% :align: center The variable table with controller, address, type, colour and formula. Each row of the variable table describes one value of a controller: .. list-table:: :header-rows: 1 :widths: 25 75 * - Column - Meaning * - Name - Unique name (also used as CSV column header). The character ``;`` is not allowed. * - Controller - Controller the variable is read from (choice from the controller table). It determines the driver and thus the address notation and the possible types. * - Chart › Y axis - Assignment of the variable (choice list or drag & drop, see below). * - Address - Address in the driver's notation, e.g. ``DB10.DBD4`` (``s7``), ``Anlage_DB.Motor[2].Drehzahl`` (``tia``), ``Program:Main.Druck`` (``clx``) or ``40001`` (``modbus``). The cell's tooltip shows examples for the driver of the selected controller. Details in the chapter `Controllers and drivers `__. * - Type - Data type, choice of the types the driver can read (e.g. ``BOOL``, ``INT``, ``DINT``, ``REAL``, ``LREAL`` …). If the controller of a variable is changed and the new driver does not know the type, it stays visible and is reported as an error when saving. * - Colour - Line colour; a click opens the colour picker. * - Record - Active (default): the variable is read from the controller and stored (CSV file, database, report). Off: the variable stays in the configuration with all its settings but is **not read** – this way variables can be prepared and added to or removed from the recording as needed. Formulas, triggers and PID tuning cannot use variables that are not recorded (message when saving). * - Display - Active (default): the variable appears in the charts and in the value/ruler table (logger, web server, report, Grafana dashboard). Off: the variable is recorded but not displayed. Only recorded variables can be displayed. * - Value display - Active: the variable appears in the logger's value/ruler table. * - Bars - Active: a narrow bar is shown for the variable next to the chart. * - Test value - Result of **Test connection**. * - Formula - Calculated variables only: the formula (double-click opens the editor). .. _variablen-suchen: Searching and filtering variables ---------------------------------------------------------------------- .. figure:: images/en/config_variablen_filter.png :alt: Search field and filters above the variable table :width: 90% :align: center Search field and filters above the variable table. Above the variable table there are a **search field** and two choice lists (``Ctrl+F`` jumps to the search field): * **Search text** – searches name, address, formula, assignment (chart › Y axis), type and controller; case does not matter. Several words must all match (``temp db10``), ``*`` and ``?`` are wildcards (``DB?.DBD*``), a word with a leading ``-`` excludes (``temp -setpoint``). * **Controller** – only variables of one controller (calculated variables stay visible). * **Kind** – *read only*, *computed only*, *without address* (incomplete rows), *not recorded* or *not displayed*. In the variable tree on the left, variables that are not recorded or not displayed are shown in grey with the note *(not recorded)* or *(not displayed)*. On the right you see how many variables are currently shown (*12 of 340*); the search field has a yellow background while a filter is active. Hidden variables stay in the configuration and are saved as well. **Remove** deletes only selected, visible rows. A newly created variable that does not match the filter resets the filter. Assignment by drag & drop ---------------------------------------------------------------------- Variables can be moved in the tree with the mouse: * **Drop onto a Y axis:** the variable then belongs to this axis. * **Drop onto another variable:** the variable takes over the Y axis (and thus the chart) of the target variable. * **Drop onto a chart:** the variable is assigned to the first Y axis of this chart. The choice list *Chart › Y axis* in the table and the tree are always in sync. .. _berechnete-variablen: Calculated variables (formulas) ---------------------------------------------------------------------- .. figure:: images/en/formeleditor.png :alt: Formula editor :width: 90% :align: center The editor for calculated variables. Besides the variables read from the PLC you can create **calculated variables** whose values the logger computes from other variables at every measurement. They appear like normal variables in charts, bars, legend, value table and in the CSV file. **Calculated variable…** opens the editor: * **Name** of the new variable. * **Formula** in the text field. Variables are written in curly braces, e.g. ``({Temp_Vorlauf} + {Temp_Ruecklauf}) / 2``. A double-click in the variable list inserts the name, a double-click in the function list the function. * **Check / calculate:** the editor checks the formula (syntax, known variables) and calculates it with freely entered **test values**. The result appears directly below. The new variable is assigned to the selected chart or Y axis (changeable like any variable). Double-clicking the *Formula* column opens the editor again. Allowed are: .. list-table:: :header-rows: 1 :widths: 30 70 * - Element - Example / meaning * - Arithmetic operators - ``+ - * / // % **`` * - Comparisons, logic - ``< > <= >= == !=``, ``and``, ``or``, ``not`` * - Condition - ``100 if {Druck} > 5 else 0`` * - Constants - ``pi``, ``e``, ``tau`` * - Mathematics - ``abs, min, max, sqrt, sin, cos, tan, asin, acos, atan, atan2, exp, ln, log10, log, floor, ceil, round, hypot, radians, degrees, sign, clamp`` * - Time functions - ``ddt(x)`` derivative per second, ``integ(x)`` integral (x · s), ``avg(x, n)`` moving average over *n* measurements Examples: .. code-block:: text {Prozess.Temperatur} * 1.8 + 32 conversion °C to °F {Druck_Ein} - {Druck_Aus} differential pressure avg({Durchfluss}, 20) smoothed flow integ({Durchfluss}) / 3600 total quantity (flow in 1/h) clamp({Fuellstand}, 0, 100) limited to 0 … 100 Notes: * If a value cannot be computed (division by 0, missing measurement, invalid range such as ``sqrt`` of a negative number), the result is *no value* (empty CSV field, gap in the curve). * A calculated variable may only use variables that are **further up** in the table (real variables always, calculated ones only if defined earlier). This is checked when saving. * If a variable is renamed, formulas using it must be adapted. The name in the formula must match exactly. * For security reasons no arbitrary program code is executed, only the elements listed above. * ``ddt``, ``integ`` and ``avg`` keep their state during the recording and start anew with every **▶ Start**. * Calculated variables are not read from the PLC and are missing in **Test connection**. .. _blocklesemodus: Block read mode ---------------------------------------------------------------------- .. figure:: images/en/blockeditor.png :alt: Block editor :width: 90% :align: center The block editor with block table and element tree (name and target per element). Many values of the same kind that lie one after another in the controller are read by the **block read mode** with as few as **one request**; the values are then assigned individually. What a block is depends on the driver: .. list-table:: :header-rows: 1 :widths: 15 85 * - Driver - Block * - ``s7`` - **Start address** (e.g. ``DB10.DBD0``, ``MW100``) + count; the elements follow without gaps (``DB10.DBD0``, ``DB10.DBD4``, ``DB10.DBD8`` …; bitwise for ``BOOL``). Read with one request. * - ``tia`` - **Array without index** (e.g. ``Mess_DB.Werte``) + **first index** (as in TIA, e.g. 1 for ``Array[1..100]``) + count. * - ``clx`` - **Array tag without index** (e.g. ``Messwerte``, ``Program:Main.Temp``) + **first index** + count. BOOL arrays are bit-packed and cannot be read as a block. * - ``modbus`` - **Start address** (e.g. ``40001`` or ``HR0``) + count; the elements follow without gaps (2 registers each for ``REAL``: ``40001``, ``40003`` …). The driver merges neighbouring addresses anyway; here a block is mainly a convenient way of creating many variables. * - ``modbus_rtu`` - like ``modbus``. * - ``opcua``, ``ads`` - **Array node / array name** (without index) + **first index** + count; read in one request. * - ``slmp``, ``kvhostlink``, ``toyopuc``, ``fins``, ``logo`` - **Start device / address** (e.g. ``D100``, ``DM100``, ``D0100``, ``VW100``) + count; elements without gaps (2 words each for ``REAL``), consecutive bits for ``BOOL``. * - ``pccc`` - **First element** of an N, F, L or B file (e.g. ``N7:0``) + count. * - ``s5as511`` - **Start address** (e.g. ``DB10.DW0``, ``MB0``, ``E0.0``) + count; elements without gaps. **Blocks (block read mode)…** opens the editor. Each row is a block with the following data: .. list-table:: :header-rows: 1 :widths: 25 75 * - Field - Meaning * - Name - Name of the block. Each element becomes the variable ``Name[0]``, ``Name[1]``, …, ``Name[n-1]``. Not allowed: ``; { } [ ]``. * - Controller - Controller the block is read from (determines the driver). * - Start address / array - See the table above; the tooltip shows the driver's notation. * - First index - Only for drivers with arrays (``tia``, ``clx``, ``opcua``, ``ads``); otherwise disabled. * - Format - Data type of the elements (choice of the driver). * - Count - Number of values (1 to 1000). * - Ring buffer - Number of records of a ring buffer (see `Ring buffer `__); *off* = normal block. Drivers ``s7``, ``tia`` and ``clx`` only. * - Chart › Y axis - Assignment of all elements of the block (single elements can be assigned differently in the tree, see below). * - Colour - The first element gets this colour, the others differ in hue. * - Value display / bars - Apply to all elements of the block (bars are off by default). * - Range - Computed display, e.g. ``DB10.DBD0 … DB10.DBD76 (80 Bytes)`` or ``Messwerte[0] … Messwerte[19]``. Example (``clx``): array tag ``Messwerte`` (``REAL[100]``), first index 10, count 20 reads ``Messwerte[10]`` to ``Messwerte[29]`` with one request and creates the variables ``Block[0]`` to ``Block[19]``. Example (``s7``): start address ``DB5.DBD0``, format ``REAL``, count 20 reads bytes 0 to 79 of DB 5. With ``tia``, ``clx``, ``opcua``, ``ads`` and ``s7`` (from the DB source), arrays can also be taken over as a block directly in the selection dialog (select the array, **Selected array as block…** or **Array as block …**, or double-click). **Test selected block** reads the block once from the controller and shows the first values and the read time. Notes: * The block elements are normal variables: they appear in charts, legend, value table, bars and CSV file and can be used in **formulas**, e.g. ``{Messwerte[3]} - {Messwerte[4]}``. * **Record and display per element:** In the tree of the block editor every element has the check boxes *Record* and *Display*. Elements that are not recorded are not stored (CSV file, database, report); recorded elements without *Display* do not appear in the charts and the value table. **The block is always read completely** – elements that are not recorded are therefore still available to formulas and triggers. The displayed elements are distributed over the charts as usual. Below the tree, **Set for all** sets *record and display*, *record only* or *do not record* for all elements of the selected block. The block row in the tree shows how many elements are recorded and displayed; in the configuration file the exceptions are stored under ``nicht_aufzeichnen`` and ``nicht_anzeigen`` (list of element indices). * **Renaming elements:** In the lower part of the block editor a **tree** shows all blocks with their elements. Double-click the *Name* column to give an element a name of its own, e.g. ``Supply pressure`` instead of ``Messwerte[1]``. An empty name restores the default name. The names must be unique and must not contain ``; { }``. In the configuration file they are stored under ``elementnamen`` of the block. * **Elements in different charts:** In the tree of the block editor every element has a choice list *Chart › Y axis* in the last column. *(like block)* uses the target of the block, every other entry shows this element in another chart or on another Y axis. **Set for all elements of the selected block** applies the chosen target to all elements. In the configuration file different targets are stored under ``elementziele`` (index: [chart, axis]). * In the variable tree of the configuration each block appears as one row (``▦ Block …``) under its Y axis. **Remove** deletes the selected block. * The range must exist completely in the controller (array large enough, DB long enough, registers present), otherwise reading the block fails; the other variables are still read. * Many elements mean many curves: split large blocks over several charts or Y axes or switch off *Display* or *value display* for individual elements. .. _ringpuffer: Ring buffer (cycle-synchronous recording) ---------------------------------------------------------------------- Normally the logger polls the controller at the configured read interval. How long a request takes varies with the network and the load of the controller; cycles in between are missing, and the time stamp is the time on the PC. For **cycle-synchronous, gap-free** recording – e.g. every 10 or 50 ms – the controller collects the values itself: a small block writes one **record** (number, time, values) per cycle or cyclic interrupt into a **ring buffer**. The logger fetches the new records at the read interval (e.g. every 250 ms) and turns each record into a row of its own with the **time stamp of the controller**. The sampling rate thus depends only on the controller, not on the network. Possible with the drivers ``s7`` (S7-300/400, S7-1200/1500 with PUT/GET), ``tia`` (S7-1200/1500 without PUT/GET) and ``clx`` (ControlLogix, CompactLogix). **1. Load the block into the controller.** The button **PLC templates …** in the block editor opens the folder ``vorlagen`` with ready-made blocks: .. list-table:: :header-rows: 1 :widths: 35 40 25 * - File - Controller - Driver * - ``Ringpuffer_S7-300_400.scl`` - S7-300/400 (SCL source for STEP 7 V5.x) - ``s7`` * - ``Ringpuffer_S7-300_400_FB.scl`` - S7-300/400 as function block with 20 inputs: the buffer is in the instance DB (several instances = several ring buffers). Start address ``DBX80.0``, because the inputs occupy bytes 0 to 79. - ``s7`` * - ``Ringpuffer_S7-1200_1500.scl`` - S7-1200/1500 (SCL source for TIA Portal: *External source files*) - ``tia`` or ``s7`` * - ``Ringpuffer_S7-1200_1500_FB.scl`` - S7-1200/1500 as function block with 20 inputs: the buffer is in the instance DB ``Cycl_Rec_DB`` (several instances = several ring buffers). ``tia``: start address ``Cycl_Rec_DB`` (the FB may be optimized); absolute ``DBX80.0`` (FB not optimized, as supplied). - ``tia`` or ``s7`` * - ``Ringpuffer_ControlLogix.st`` - ControlLogix/CompactLogix (Structured Text, data types described) - ``clx`` The templates write 10 values of type REAL into a buffer with 100 records; both numbers can be adjusted (notes at the top of each file). Call the block where the values arise regularly: in a cyclic interrupt (S7-300/400: OB35, S7-1200/1500: *Cyclic interrupt* OB30, Logix: periodic task) with e.g. 10 ms or 50 ms. **2. Create the ring buffer in the block editor.** A block becomes a ring buffer as soon as the column **Ring buffer** contains the number of records (*off* = normal block): .. list-table:: :header-rows: 1 :widths: 25 75 * - Field - Ring buffer * - Start address - ``s7``: address of the counter at the start of the buffer in a **non-optimized** data block, e.g. ``DB100.DBX0.0``. ``tia``: **name of the buffer** – the DB or the structure with ``Zaehler`` and ``Daten``, e.g. ``PLC_Ringpuffer``, ``Cycl_Rec_DB`` or ``Anlage_DB.Puffer``; the block may be **optimized**. Alternatively, as with ``s7``, the absolute address (non-optimized only, faster for large buffers). ``clx``: tag of the buffer, e.g. ``Puffer`` or ``Program:Main.Puffer``. * - Format - Data type of the values: ``INT``, ``DINT``, ``REAL`` (``s7``/``tia`` additionally ``WORD``, ``UINT``, ``DWORD``, ``UDINT``, ``LREAL``; ``clx`` additionally ``UINT``, ``UDINT``, ``LREAL``). Store binary signals as ``INT`` 0/1. * - Count - Values per record (as in the controller). * - Ring buffer - Records in the buffer (as in the controller). As with blocks, the elements are called ``Name[0]``, ``Name[1]`` … and can be renamed and assigned to other charts in the tree. **Test selected block** fetches the buffer once and shows the counter, the number of records, their mean interval and the latest values. **3. Read interval and buffer size.** The **Interval** of the controller (table of controllers) is the read interval here: it only determines how often the buffer is fetched. The buffer must hold the records of at least three read intervals: *records ≥ 3 × read interval ÷ cycle time*. Example: 10 ms cyclic interrupt and 250 ms read interval → at least 75 records (the templates have 100); 50 ms and 500 ms → at least 30. **Buffer layout** (S7 with absolute address: non-optimized DB, even start address; ``tia`` with a name and Logix: exactly these names; with ``tia`` the arrays may also start at 1): .. code-block:: text Zaehler DINT number of records written so far (1, 2, 3 …) Daten[0..N-1] N records; record number n is stored in Daten[n MOD N] Seq DINT number of the record (= Zaehler when written) Zeit DINT time in ms (see below) Werte[0..M-1] M values in the chosen format The controller writes in this order: values, time, Seq, finally the counter. The logger reads the counter, then the new records and the counter once more; a record only counts if *Seq* has the expected number and it could not have been overwritten during reading. **Time:** S7-300/400 ``TIME_TCK`` (ms since the CPU restart), S7-1200/1500 and Logix ms since midnight from the controller's clock. The logger removes overflows (midnight, 2³¹) and attaches the time to the PC clock: the latest record of the first fetch gets the current time, all others their distance to it according to the controller. The intervals between rows are thus exactly those of the controller; the absolute time is as accurate as the PC clock (a deviating controller clock is followed slowly). Notes: * Lost records (buffer too small, connection interrupted for a long time) are reported in the status line: “Ring buffer …: n records lost”. After a short interruption the records are fetched from the buffer as long as it still contains them. * A restart of the controller resets the counter; the logger detects this and starts again. * Because the records only arrive when they are fetched, charts and value table show all values delayed by about two read intervals when ring buffers are used (the rows are sorted by their time). CSV file and database contain every record with its time. * Normal variables of the same or other controllers are read as usual; in the rows of a ring buffer they keep their last value. * Formulas, triggers, reports and triggered recording see every record – a trigger thus also fires on a pulse of just one cycle. * In demo mode, ring buffer elements deliver simulated values like normal variables. Selecting variables from the controller ---------------------------------------------------------------------- .. figure:: images/en/symbolbaum.png :alt: Selection dialog :width: 90% :align: center Example: tag list of a ControlLogix (driver ``clx``); tags already created are ticked. The button above the variable table has a different name depending on the driver of the selected controller and opens its selection dialog (with several controllers you are asked first which one): .. list-table:: :header-rows: 1 :widths: 15 25 60 * - Driver - Button - Source of the variables * - ``tia`` - Select from variable list… - Variable list directly from the CPU (all data blocks, memory, inputs and outputs with structure and type, including optimized blocks). * - ``clx`` - Select from tag list… - Tag list directly from the controller (pycomm3): controller and program tags, UDTs, arrays. * - ``s7`` - Select from DB source… - Exported DB sources from TIA Portal/STEP 7 (the PLC delivers no names via PUT/GET); comparison of the DB sizes with the PLC, arrays as block. * - ``opcua`` - Select from OPC UA server… - Address space of the server (folders, variables with data type, arrays as block). * - ``ads`` - Choose from TwinCAT… - Symbol table of the TwinCAT controller (tree by name parts, type, comment, arrays as block). * - other drivers - – - Modbus, MELSEC, Omron, KEYENCE, TOYOPUC, LOGO!, MicroLogix and S5 deliver no names; enter the addresses by hand as per program or device manual. General procedure: #. **Load.** When opened for the first time, the list is loaded from the controller (``tia``, ``clx``) or the DB sources are imported (``s7``, **Import DB source…**). Loaded lists are cached per controller in the folder ``taglisten`` of the data folder and are shown immediately the next time, even without a connection. The paths of the S7 DB sources are stored in the configuration. #. **Search.** Structures and arrays can be expanded; the **filter** field searches by name. #. **Select.** Tick readable values. Variables already created are ticked and greyed out. Types that cannot be recorded (e.g. ``STRING``) are shown in grey. #. **Arrays as block** (``tia``, ``clx``, ``opcua``, ``ads``, ``s7``): select the array, **Selected array as block…** (``s7``: **Array as block …**) or double-click, set first index and count. With ``s7`` this applies to one-dimensional arrays of numbers or BOOL; the start address is calculated from the DB source. #. **Take over.** Under *Create new variables in* choose the chart or Y axis and press **Take over selection**. Address and type come from the controller or source. #. **Check.** Check the values read with **Test connection**. Details about the dialogs are given for each driver in the chapter `Controllers and drivers `__. Testing the connection ---------------------------------------------------------------------- **Test connection** connects to each controller in turn (via its driver), reads its variables once and enters the result in the *Test value* column. Errors of single variables are shown there in plain text (e.g. address does not exist, wrong type, access denied, Modbus exception “illegal address”); if a controller cannot be reached, a message box reports it with name and connection. When saving, the driver of each controller checks the addresses formally (notation, suitable type, e.g. ``BOOL`` for coils). Whether an address actually exists in the controller is only shown by the connection test. Saving and loading ---------------------------------------------------------------------- The **File** menu of the configuration program contains: * **New** – empty configuration with one controller; the file name is asked for when saving for the first time. * **Open…** (``Ctrl+O``) – loads a configuration file (JSON) with **any name**, including configurations of the S7, TIA and CLX data loggers (see `Importing configurations of the single programs `__). * **Save** (``Ctrl+S``) and **Save as…** (``Ctrl+Shift+S``) – write to the current or a new file (the extension is always ``.json``). Before saving it is checked that controller and variable names are unique and not empty, the connection parameters and addresses are valid for the respective driver, the formulas are correct and, for fixed Y axes, *Y max* is greater than *Y min*. * **Convert INI file …** – convert older INI configurations once to JSON (see `Converting older INI files `__). * **Start logger with this configuration** (``Ctrl+R``) – saves and starts the logger with this file. * **Start IO check with this configuration** – saves and starts the `IO check `__ with the controllers of this file (separate program). * **Show/stop headless loggers …** – show running headless loggers and stop them cleanly (see `Headless operation (recording only) `__). * **Export Grafana dashboard …** – dashboard with the layout of the logger as a JSON file for Grafana (see `Database recording `__). The window title shows project name and file name. The last used file is remembered (file ``plc_last.txt``); the logger and the configuration program open it again at the next start without parameters. .. note:: The logger reads the configuration at every **start**. Changes therefore only take effect after pressing **▶ Start** again. Importing and exporting variables ---------------------------------------------------------------------- The **Import/Export** button below the variable table exchanges the variable list with an **Excel** (``.xlsx``) or **CSV file** – useful for editing long lists in Excel or for taking over an address list of the controller. **ODS files** (LibreOffice/OpenOffice Calc, ``.ods``) can be read as well. * **Export variables (CSV/Excel) …** writes all variables of the table (without block elements, see `Block read mode `__) with the columns ``Name``, ``Steuerung``, ``Diagramm``, ``Y-Achse``, ``Adresse``, ``Typ``, ``Farbe``, ``Aufzeichnen``, ``Anzeigen``, ``Werteanzeige``, ``Balken`` and ``Formel``. The column names are always German, so files can be exchanged between languages. * **Import variables (CSV/Excel/ODS) …** reads such a file. The first row contains the column names; only ``Name`` is mandatory, order and case do not matter. CSV files may use semicolon, comma or tab as separator. When importing: * If variables already exist, the program asks whether they should be **replaced** or the new ones **appended**. When appending, variables with an existing name are skipped. * ``Steuerung`` is the name of a controller from the controller table; empty or unknown = first controller (unknown names are reported). * ``Diagramm`` and ``Y-Achse`` are names; missing charts and axes are created, empty = first chart or first axis. * ``Typ`` empty = default type of the driver; ``Farbe`` as ``#rrggbb``, empty = colour from the palette. * ``Aufzeichnen``, ``Anzeigen``, ``Werteanzeige`` and ``Balken``: ``ja``/``nein`` (also ``yes``/``no``, ``1``/``0``, ``x``); empty = yes. * If ``Formel`` is filled, a calculated variable is created (``Adresse`` and ``Typ`` are then ignored). As with manual input, addresses and formulas are only checked when **saving**. Structure of the configuration file (JSON) ---------------------------------------------------------------------- The configuration is saved as a **JSON file** (UTF-8, indented) and can also be edited by hand if required – with any text editor, preferably one that checks JSON (e.g. Notepad++, Visual Studio Code). The keys are German. Example: .. code-block:: json { "format": "PLC Datenlogger Konfiguration", "version": 1, "einstellungen": { "projekt": "Prüfstand 3", "csv_ordner": "logs", "csv_name": "log", "max_records": 100000, "archiv_ordner": "archiv", "fenster_s": 60, "anordnung": "untereinander", "balken": true, "archiv_beenden": true, "seite_anordnung": "raster", "raster_spalten": 2, "web_aktiv": true, "web_host": "0.0.0.0", "web_port": 8080, "web_intervall_ms": 1000, "headless": false, "treiberdaten": { "s7": { "symbolquellen": "C:/Projekt/Mess_DB.db" } } }, "steuerungen": [ { "name": "Presse", "treiber": "tia", "intervall_ms": 100, "aktiv": true, "ip": "192.168.0.1", "port": 102, "tls": "auto", "passwort": "", "rolle": "hmi", "tags_je_anfrage": 50 }, { "name": "Altanlage", "treiber": "s7", "intervall_ms": 500, "aktiv": true, "ip": "192.168.0.20", "rack": 0, "slot": 2 }, { "name": "Kessel", "treiber": "clx", "intervall_ms": 200, "aktiv": true, "ip": "192.168.1.10", "pfad": "1,0", "cpu": "controllogix", "timeout_ms": 2000 }, { "name": "Zaehler", "treiber": "modbus", "intervall_ms": 1000, "aktiv": true, "ip": "192.168.0.50", "port": 502, "unit": 1, "wortfolge": "CDAB", "max_register": 120, "luecke": 8, "timeout_ms": 2000 } ], "diagramme": [ { "name": "Prozess", "seite": "Prozess", "achsen": [ { "name": "Temperatur", "auto": true, "y_min": 0.0, "y_max": 100.0 }, { "name": "Leistung", "auto": false, "y_min": 0.0, "y_max": 50.0 } ] } ], "variablen": [ { "name": "Kraft", "adresse": "Presse_DB.Kraft", "typ": "REAL", "farbe": "#d62728", "wert_anzeigen": true, "diagramm": 1, "achse": 1, "balken": true, "formel": "", "steuerung": 1 }, { "name": "Temp_Alt", "adresse": "DB10.DBD4", "typ": "REAL", "steuerung": 2 }, { "name": "Temperatur_Kessel", "adresse": "Program:Kessel.Temperatur", "typ": "REAL", "steuerung": 3 }, { "name": "Wirkleistung", "adresse": "30013", "typ": "REAL", "steuerung": 4 } ], "bloecke": [ { "name": "Messwerte", "adresse": "Messwerte", "start": 0, "typ": "REAL", "anzahl": 20, "diagramm": 1, "achse": 1, "farbe": "#1f77b4", "wert_anzeigen": true, "balken": false, "steuerung": 3, "elementziele": { "3": [ 1, 2 ] } } ] } Structure: .. list-table:: :header-rows: 1 :widths: 22 78 * - Key - Content * - ``format``, ``version`` - File identifier and version of the structure (currently 1). * - ``einstellungen`` - Settings: project, recording (CSV, archive, database, trigger recording, reports), display, web server, headless. * - ``steuerungen`` - List of controllers (order = number referred to by ``steuerung``). * - ``diagramme`` - List of charts, per chart the list ``achsen`` (Y axes) and possibly the PID settings (``pid_…``). * - ``variablen`` - Normal and calculated variables (``formel`` not empty). * - ``bloecke`` - Blocks of the block read mode; ``elementnamen`` = own names of single elements (``{"1": "Supply pressure"}``), ``elementziele`` = different chart and axis of single elements (``{"3": [2, 1]}``). * - ``trigger`` - Triggers of the event log. Numbers and booleans are stored with their type (``200``, ``1.5``, ``true``/``false``). Missing keys get their default value when loading, unknown ones are ignored. If the file is not valid JSON (e.g. a forgotten comma), the program reports the line of the error. Explanations: * ``treiber`` is the ID of the driver; the other keys of an entry in ``steuerungen`` (except ``name``, ``intervall_ms``, ``aktiv``) are its connection parameters (see `Controllers and drivers `__). Unknown keys are ignored, missing ones get the driver's default value. * ``adresse`` is the address in the notation of the controller's driver. For blocks, ``adresse`` is the start address or the array name and ``start`` the first index (drivers with arrays only). * ``treiberdaten`` contains driver-specific data as an object (e.g. the paths of the S7 DB sources). * ``diagramm``, ``achse`` and ``steuerung`` are numbers starting at 1. * ``seite_anordnung`` is empty (automatic), ``untereinander`` (stacked), ``nebeneinander`` (side by side) or ``raster`` (grid); ``raster_spalten: 0`` chooses the number of columns automatically. * The variables of a block (``Messwerte[0]`` …) are created when loading and are not listed under ``variablen`` in the file. * The TIA password is stored in **plain text** in the file. .. _ini-umwandeln: Converting older INI files ---------------------------------------------------------------------- Earlier versions stored the configuration as an INI file. These files are **no longer opened directly** but converted once into a JSON file; the INI file itself remains unchanged: * **Configuration program › File › Convert INI file …** – choose one or more INI files; a ``.json`` file with the same name is created next to each. For a single file the result is opened immediately. * If an INI file is chosen in the configuration program (Open, start screen), it offers the conversion directly. * For many files at once (Python sources): .. code-block:: console python tools/ini2json.py plant1.ini plant2.ini # -> plant1.json, plant2.json python tools/ini2json.py old.ini -o new.json -f # other name, overwrite When started with an INI file, the logger reports that it has to be converted. If an INI file was opened last and the converted ``.json`` file already exists next to it, that file is used automatically. All contents – including triggers, PID settings and blocks – are taken over. .. _treiber: Controllers and drivers ====================================================================== Each controller of the configuration has exactly one driver. It defines which connection parameters exist, how variables are addressed, which data types can be read, what blocks look like and whether there is a selection dialog. Any drivers can be mixed in one configuration. **How well is each driver tested?** Automatic tests run on every upload; where a third-party, widely used counterpart exists, they test the driver against its simulator. So far ``s7`` and ``clx`` have been tried with real controllers, ``tia`` with the simulated CPU of S7-PLCSIM Advanced: .. list-table:: :header-rows: 1 :widths: 20 80 * - Driver - Tested * - ``s7`` - **With a controller** (S7-300/400, also ring buffer; Windows and Raspberry Pi with Ubuntu 24.04); automatically against the S7 server of python-snap7 (single values, bits, blocks, ring buffer). * - ``clx`` - **With a controller** (normal reading and blocks; Windows and Raspberry Pi with Ubuntu 24.04); the ring buffer only against a simulated libplctag. * - ``tia`` - **With S7-PLCSIM Advanced** (simulated S7-1500) tried successfully: without PUT/GET, with TLS, variable list from the CPU, reading from two optimized DBs, ring buffer by its name, different access levels of the CPU without password (reading or message). Not yet tried: login with password, real CPU. Automatically: ring buffer with absolute address against the S7CommPlus emulator of s7commplus, with a name (optimized) against a simulated controller. * - ``modbus`` - Automatically against the Modbus TCP server of pymodbus (all four tables, bits, REAL/DINT, word order). * - ``opcua`` - **Over the network against the logger's own OPC UA server** (Raspberry Pi as server, PC as client): selection dialog, cyclic read, subscription, reconnect after a server failure, Basic256Sha256 (sign and encrypt) with login. Not yet tried: array as block, the server of a real PLC. Automatically against an OPC UA server of asyncua (numbers, BOOL, array as block). * - ``logo``, ``pccc``, ``modbus_rtu``, ``ads``, ``slmp``, ``fins``, ``kvhostlink``, ``toyopuc``, ``s5as511`` - Not yet tried with a controller or a simulator. Experience reports and error reports (e.g. via GitHub) are welcome. Driver ``s7`` – Siemens S7 (PUT/GET, snap7) ---------------------------------------------------------------------- For S7-300/400 and S7-1200/1500 via classic S7 communication with **absolute addresses**. Library: ``python-snap7``. .. list-table:: Connection parameters :header-rows: 1 :widths: 20 80 * - Parameter - Meaning * - IP address - Address of the CPU or CP. * - Rack - Rack, almost always ``0``. * - Slot - Slot of the CPU: S7-300 ``2``, S7-1200/1500 ``1`` (or ``0``), S7-400 as per hardware configuration. **Preparation:** On S7-1200/1500 enable *“Permit access with PUT/GET communication from remote partner”* in the CPU properties in TIA Portal. Only data blocks **without** “Optimized block access” are read (use the ``tia`` driver for optimized blocks). TCP port 102. **Addresses** (German or English mnemonics; the type comes from the *Type* column, the size letter X/B/W/D in the address is only a writing aid): .. list-table:: :header-rows: 1 :widths: 40 60 * - Address - Meaning * - ``DB10.DBX4.2``, ``DB10.DBB4``, ``DB10.DBW4``, ``DB10.DBD4`` - Data block 10, byte 4 (bit 2) * - ``DB10.4``, ``DB10.4.2`` - Short form: DB number, byte[, bit] * - ``M5.0``, ``MB5``, ``MW10``, ``MD20`` - Memory (flags) * - ``E0.1``, ``EB0``, ``EW64`` or ``I0.1``, ``IB0``, ``IW64`` - Inputs (process image) * - ``A1.0``, ``AB1``, ``AW2`` or ``Q1.0``, ``QB1``, ``QW2`` - Outputs (process image) When saving, the address is written uniformly to match the type (e.g. ``DB10.4`` with type ``REAL`` → ``DB10.DBD4``). **Types:** ``BOOL``, ``BYTE``, ``USINT``, ``SINT``, ``CHAR``, ``WORD``, ``UINT``, ``INT``, ``DWORD``, ``UDINT``, ``DINT``, ``REAL``, ``TIME`` (ms), ``LWORD``, ``ULINT``, ``LINT``, ``LREAL``. **Blocks:** start address + count, elements without gaps; a block is read with **one** request. Single variables are read individually – with many variables in one DB a block is considerably faster. **Selection dialog “Select from DB source…”:** Via S7 communication the PLC delivers **no names and structures**. The tree of data blocks (DB › structure › variable) is therefore built from **DB sources**: #. In TIA Portal select the DB (and the UDTs needed), right-click *Generate source from blocks*; in STEP 7 save the DB as source (``.db``/``.awl``). #. In the dialog choose **Import DB source…** (several files possible). If the DB number is missing in the source (TIA), it is asked for. #. Optionally **Compare with PLC**: compares the computed size of each DB with the size in the PLC (✓ or ⚠ – a difference indicates an optimized block or an outdated source). #. Tick variables (a tick on a structure/array/DB selects everything in it) and take them over. The name of the variable is the symbol path. The paths of the sources are stored in the configuration (``treiberdaten``) and read again the next time. Driver ``tia`` – Siemens S7-1200/1500 symbolic (S7CommPlus) ---------------------------------------------------------------------- Symbolic access like TIA Portal and Siemens HMIs – also to **optimized** data blocks, **without** PUT/GET. Library: ``s7commplus``. .. list-table:: Connection parameters :header-rows: 1 :widths: 25 75 * - Parameter - Meaning * - IP address - Address of the CPU. * - Port - ISO-on-TCP port, default ``102``. * - TLS - *Automatic* (TLS if the CPU offers it), *Off*, *On (force TLS)*. Newer firmware (S7-1500 from V3.1, S7-1200 from V4.7, projects from TIA V19) communicates only encrypted. * - Password - Password of the access level if the CPU protects read access (stored in plain text in the configuration file). * - Role (Advanced) - *HMI* (default), *Engineering*, *PG*. * - Variables per request (Advanced) - Maximum number of variables per read request (default 50); larger quantities are split. **Preparation:** usually none. Variables must be “Accessible from HMI/OPC UA/Web API” (default). Each CPU allows only a limited number of HMI connections; the logger uses one per controller. TCP port 102. **Addresses:** symbolic names as in TIA Portal: .. code-block:: text Mess_DB.Temp variable in a data block Anlage_DB.Motor[2].Drehzahl structure member in an array MArea.Start_Merker memory (PLC tag) IArea.Taster_1 input QArea.Lampe output **Types:** ``BOOL``, ``BYTE``, ``WORD``, ``DWORD``, ``LWORD``, ``SINT``, ``INT``, ``DINT``, ``LINT``, ``USINT``, ``UINT``, ``UDINT``, ``ULINT``, ``REAL``, ``LREAL``, ``TIME``, ``LTIME``, ``S5TIME``, ``CHAR``, ``WCHAR``. **Blocks:** array without index + first index (as in TIA, e.g. ``1`` for ``Array[1..100]``) + count. **Selection dialog “Select from variable list…”:** loads the variable list directly from the CPU (data blocks, memory, inputs/outputs with structure and type) and caches it in the folder ``taglisten``. .. warning:: ``s7commplus`` is an **unofficial** implementation, not from Siemens. Test new configurations on a plant that is not safety-relevant first. Driver ``logo`` – Siemens LOGO! (0BA7/0BA8) ---------------------------------------------------------------------- For LOGO! 7 (0BA7) and LOGO! 8 (0BA8, 8.FS4, 8.3, 8.4) via S7 communication; library ``python-snap7`` (as for the ``s7`` driver). **Set up in the LOGO!:** In LOGO!Soft Comfort under *Tools › Ethernet Connections* (LOGO! 8: *Online Settings › Access control*) enable HMI access or create a **server connection (S7)**. The TSAP values of this connection must match the parameters here: *Local TSAP* of the LOGO! = **TSAP of the LOGO!**, *Remote TSAP* = **TSAP of the logger**. LOGO! 8 with HMI access enabled: ``02.00`` and ``01.00`` (default). .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address - Address of the LOGO!. * - Device - *LOGO! 8* or *LOGO! 7* – determines where I, Q, M, AI, AQ, AM are located in the variable memory (VM). * - TSAP of the LOGO! / TSAP of the logger - As ``hh.hh`` (e.g. ``02.00``, ``20.00``) or number (``0x0200``). **Addresses:** variable memory directly (``V10`` or ``VB10`` = byte, ``VW12`` = word, ``VD20`` = double word, ``V10.3`` = bit) or the LOGO! operands ``I1`` … ``I24``, ``Q1`` … ``Q20``, ``M1`` … ``M64``, ``NI``, ``NQ`` (BOOL) and ``AI1`` … ``AI8``, ``AQ``, ``AM1`` … ``AM64``, ``NAI``, ``NAQ`` (INT). Values in the VM are “big endian” as with S7. Neighbouring addresses are merged into one request; blocks: start address in the VM (e.g. ``VW100``), the elements follow without gaps. Driver ``clx`` – Allen-Bradley Logix (EtherNet/IP) ---------------------------------------------------------------------- For ControlLogix, CompactLogix and Micro800. Reading is done with **libplctag** (``plctag.dll`` / ``libplctag.so``); all tags of a controller are triggered at the same time in each cycle and combined into common CIP requests. The tag list is provided by **pycomm3**. .. list-table:: Connection parameters :header-rows: 1 :widths: 25 75 * - Parameter - Meaning * - IP address - Address of the Ethernet module (e.g. 1756-EN2T) or of the CPU with built-in Ethernet. * - CIP path - Route to the CPU, ``port,address``; backplane = port 1. ControlLogix with CPU in slot 0: ``1,0`` (slot 3: ``1,3``), CompactLogix: ``1,0``, Micro800: empty. * - Controller type - ControlLogix, CompactLogix or Micro800. * - Timeout (Advanced) - Waiting time per read cycle (default 2000 ms). **Preparation:** *External Access* of the tags *Read/Write* or *Read Only*. TCP port 44818. **Addresses:** tag names as in Studio 5000 or Connected Components Workbench: ``Temp_Kessel`` (controller tag), ``Program:Main.Druck`` (program tag), ``Anlage.Motor[2].Drehzahl``, ``Status.3`` (bit 3 of an integer, type ``BOOL``). **Types:** ``BOOL``, ``SINT``, ``INT``, ``DINT``, ``LINT``, ``USINT``, ``UINT``, ``UDINT``, ``ULINT``, ``REAL``, ``LREAL`` (read bit strings ``DWORD``/``WORD`` as ``UDINT``/``UINT``). **Blocks:** array tag without index + first index + count; libplctag splits large ranges itself. BOOL arrays not as block. **Selection dialog “Select from tag list…”:** controller tags and (tick *Program tags*) the tags of all programs, with UDTs, arrays (at most 500 elements individually) and filter; cached in the folder ``taglisten``. Driver ``pccc`` – Allen-Bradley MicroLogix / SLC 500 (PCCC) ---------------------------------------------------------------------- For the older Allen-Bradley controllers with file addresses (RSLogix 500): MicroLogix 1100/1400, SLC 5/05 and SLC 5/03/04 via an Ethernet bridge module. Library ``pycomm3`` (SLCDriver, EtherNet/IP with PCCC commands). ControlLogix, CompactLogix and Micro800 use the ``clx`` driver. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address - Address of the controller or Ethernet module. * - CIP path (Advanced) - Only behind a bridge module, e.g. ``bp/1``; otherwise empty. **Addresses** in RSLogix 500 notation: ``N7:0`` (INT), ``F8:2`` (REAL), ``L9:0`` (DINT, MicroLogix 1100/1400), ``B3:2`` (word) or ``B3:0/5`` and ``N7:10/3`` (bits, type BOOL), ``T4:0.ACC``/``T4:0.PRE``/``C5:1.ACC`` (accumulated/preset values), ``T4:0.DN`` (status bit), ``I:0/1``, ``O:0/2``, ``S:1/5``. Elements of the same N, F, L or B file that are close together are read with **one** request; blocks: first element, e.g. ``N7:0``. Driver ``modbus`` – Modbus TCP ---------------------------------------------------------------------- For all devices with Modbus TCP (also Modbus RTU devices behind a TCP gateway). No additional library. Neighbouring addresses are automatically combined into as few requests as possible (functions 1 to 4). .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address, port - Address of the device or gateway, default port ``502``. * - Device address (unit ID) - Slave/unit ID (default 1); for gateways the address on the serial bus. * - Byte/word order - Order for values spanning several registers (``DINT``, ``REAL`` …) as per device manual: ``ABCD`` big endian (default), ``CDAB`` words swapped (common, e.g. with many energy meters), ``BADC`` bytes swapped, ``DCBA`` little endian. * - Registers per request (Advanced) - Maximum number of registers in one request (1 to 125, default 120). * - Merge gaps up to (Advanced) - Addresses with a smaller distance are read in the same request (default 8 registers; 0 = only without gaps). * - Timeout (Advanced) - Time to wait for a response (default 2000 ms). **Addresses** – Modicon notation (counted from 1) or table + offset (from 0): .. list-table:: :header-rows: 1 :widths: 35 30 35 * - Modicon - from 0 - Area, function * - ``40001`` … (6 digits ``400001``) - ``HR0`` … - Holding registers, FC 3 * - ``30001`` … (``300001``) - ``IR0`` … - Input registers, FC 4 * - ``00001`` … or ``1`` … - ``C0`` … - Coils, FC 1 (type ``BOOL``) * - ``10001`` … (``100001``) - ``DI0`` … - Discrete inputs, FC 2 (type ``BOOL``) * - ``40001.3`` - ``HR0.3`` - Bit 3 of a register (type ``BOOL``, bit 0–15) ``40001`` and ``HR0`` denote the same register. If the device manual says “register 100” without anything else, it usually means ``HR100`` (= ``40101``) – if in doubt, check both with **Test connection**. ``%MW0`` (Schneider) is understood as ``HR0``. **Types:** ``BOOL``, ``INT``, ``UINT``, ``WORD`` (1 register), ``DINT``, ``UDINT``, ``DWORD``, ``REAL`` (2 registers), ``LINT``, ``ULINT``, ``LWORD``, ``LREAL`` (4 registers). **Blocks:** start address + count, elements without gaps (for ``REAL`` at a distance of 2 registers). **Errors:** If the device responds with a Modbus exception (e.g. *illegal address*), only the affected request remains without value; the message appears in the status line or as test value. Driver ``modbus_rtu`` – Modbus RTU (serial) ---------------------------------------------------------------------- For devices with Modbus RTU on RS-485 or RS-232 (frequency converters, energy meters, temperature controllers, compact controllers …), connected via a built-in interface or a USB adapter. Libraries: ``pymodbus`` (3.x or 4.x) and ``pyserial``. Addresses, data types, byte/word order, blocks and merging of neighbouring addresses are **the same as for the** ``modbus`` **driver** (``40001``/``HR0``, ``30001``/``IR0``, ``00001``/``C0``, ``10001``/``DI0``, ``40001.3``). .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - Port - Windows ``COM3`` …, Linux ``/dev/ttyUSB0``, ``/dev/ttyAMA0`` … * - Device address - Modbus slave address 1–247. * - Baud rate, parity, stop bits - As per device; usually 19200 baud, even parity, 1 stop bit (or 9600 8N2). * - Byte/word order - As for the ``modbus`` driver. * - Data bits, registers per request, gap, timeout, retries (Advanced) - Registers per request default 60 (smaller values relieve slow devices), timeout 1000 ms, 1 retry. **Several devices on one bus:** create one controller per device with the **same port** and its own device address. The controllers share the port automatically; the telegrams go onto the bus one after the other. Baud rate, parity, stop bits and data bits must be the same (otherwise the second controller reports an error). The sampling intervals of all devices together must match the bus speed – at 9600 baud a request with 10 registers takes about 30 ms. If a device does not respond, only its controller is reported as faulty (LED red); the other devices on the bus are still read. Driver ``opcua`` – OPC UA ---------------------------------------------------------------------- For all controllers and servers with OPC UA – e.g. Beckhoff TwinCAT, B&R, Codesys controllers (Wago, Festo, Schneider, Eaton …), Siemens S7-1500 and WinCC, Omron NX/NJ, Rockwell via FactoryTalk Linx Gateway, Mitsubishi iQ-R with OPC UA module, Kepware/KEPServerEX. Library: ``asyncua``. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - Endpoint - e.g. ``opc.tcp://192.168.0.10:4840`` (Codesys, TwinCAT, S7-1500: port 4840; Kepware: 49320). A path after the port belongs to it if the server requires one. * - Operating mode - *Read cyclically (Read)* (default) or *Subscription* – the server reports only changes (see below). * - Publishing interval, sampling interval (Advanced, subscription only) - How often the server sends collected changes or checks the values; ``0`` = interval of the controller. * - Security - *None*, or *Basic256Sha256*, *Aes128Sha256RsaOaep*, *Aes256Sha256RsaPss* each with *Sign* or *Sign and encrypt* – whatever the server offers. * - User, password - Empty = anonymous. The password is stored in plain text in the configuration file. * - Client certificate, private key (Advanced) - Only with security. Empty = the driver creates a self-signed certificate when connecting for the first time (folder ``opcua`` in the data folder, valid for one year). * - Timeout, nodes per request (Advanced) - Default 4 s and 500 nodes per read request (some servers allow fewer; then set e.g. 100). **Trusting the certificate:** With security, the server usually has to accept the client certificate as trusted first (TwinCAT, Codesys, S7-1500: choose “Trust” in the server's certificate store). The first connection attempt is rejected; after trusting it works. **Addresses:** the NodeId of the node as shown by the server and the engineering tool: .. code-block:: text ns=4;s=|var|CODESYS Control.Application.GVL.Temperatur Codesys ns=4;s=MAIN.fTemperatur TwinCAT ns=3;s="DB_Prozess"."Temperatur" S7-1500 ns=2;s=Kanal1.Geraet1.Temperatur Kepware ns=2;i=1001 numeric identifier The server delivers each value with its own OPC UA data type; the *Type* column is for display only. Timestamps (DateTime) are recorded as Unix time, texts cannot be recorded. **Blocks:** array node (NodeId without index) + first index + count. The section is read with an index range in **one** request. An array as single variable reports “Array – please read as block”. **Selection dialog “Select from OPC UA server…”:** connects to the server and shows the address space starting at *Objects*; folders are loaded when expanded. Tick readable variables (numbers, BOOL), take over arrays by double-click or **Selected array as block …**. The filter field searches the nodes already loaded. The name of the new variable is the path of display names. All nodes of a controller are read in each cycle with as few read requests as possible. An invalid node (e.g. *BadNodeIdUnknown*) affects only its own variable. .. figure:: images/en/opcua_subscription.png :alt: Connection settings of the opcua driver with mode Subscription :width: 75% :align: center Connection settings of the opcua driver with mode Subscription. **Subscription:** Instead of reading all nodes in every cycle, the driver sets up a subscription when connecting; the server then reports only changed values. The logger still records at the interval of the controller (with the last reported value). With many rarely changing values this saves network load and server performance. The initial values are read once; the driver checks the connection every few seconds with a small read request and reconnects if necessary. Arrays (blocks) are subscribed with an index range. Driver ``ads`` – Beckhoff TwinCAT (ADS) ---------------------------------------------------------------------- For TwinCAT 2 and 3 via the Beckhoff protocol ADS (AMS/TCP, port 48898) – without an additional library and without TwinCAT on the logger computer. (Alternatively TwinCAT also works via the ``opcua`` driver if the TF6100 server is licensed.) **Adding a route:** The controller answers ADS requests only from computers for which a **route** is configured: in the TwinCAT System Manager or XAE under *SYSTEM › Routes* (or via the TwinCAT icon on the controller) add a static route with the **AMS Net ID of this computer** (parameter *Own AMS Net ID*, default: IP address + ``.1.1``) and its IP address. Without a route the driver reports “ADS error 0x7: target machine not found”. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address - Address of the controller. * - AMS Net ID of the controller - e.g. ``5.12.34.56.1.1`` (TwinCAT shows it in the router); empty = IP + ``.1.1``. * - AMS port - ``851`` = first PLC runtime of TwinCAT 3 (``852`` … further), ``801`` = TwinCAT 2. * - Own AMS Net ID, own AMS port (Advanced) - Must match the route; empty = own IP address + ``.1.1``. * - Variables per request (Advanced) - Maximum number of parts of a sum request (TwinCAT: 500). **Addresses:** symbolic as in the PLC project – ``MAIN.fTemperatur``, ``GVL.aWerte[3]``, ``MAIN.stMotor.nDrehzahl``, TwinCAT 2 global ``.gWert`` – or memory/I/O ``%MW10``, ``%MD4``, ``%MX2.3``, ``%IW0``, ``%QX0.1`` or index group:offset (``0x4020:16``). Symbol names are resolved once when connecting; afterwards all variables are read with sum requests (up to 500 per request). After a download to the controller the driver reconnects and resolves the names again. **Blocks:** array name without index (``MAIN.aWerte``) + first index + count – the section is read in one piece. .. figure:: images/en/ads_auswahl.png :alt: Connection settings of the ads driver (AMS Net ID, ports, advanced) :width: 90% :align: center Connection settings of the ads driver (AMS Net ID, ports, advanced). **Selection dialog “Choose from TwinCAT…”:** reads the symbol table of the controller and shows it as a tree (``MAIN`` › ``Pumpe`` › ``fDruck``) with type and comment; filter field, tick variables, take over arrays of numbers as block by double-click. Driver ``slmp`` – Mitsubishi MELSEC (SLMP / MC protocol) ---------------------------------------------------------------------- For MELSEC iQ-R, iQ-F (FX5), Q (QnU, QnUDE …) and L with built-in Ethernet or Ethernet module. Protocol SLMP (MC protocol) with 3E frame, binary, via TCP or UDP. No additional library. **Preparation (GX Works):** In the Ethernet settings create a connection “SLMP” (iQ-R/iQ-F) or “MC protocol” (Q/L), **binary**, TCP or UDP, with a port and download it to the controller. The logger only reads. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address, port, protocol - As set in GX Works (e.g. port 5007, TCP). * - Series - *Q/L/iQ-F* (standard format) or *iQ-R* (extended format with 4-byte device numbers). An iQ-R understands both. * - Network no., station, target module (Advanced) - For the own station ``0``, ``255``, ``03FF``. In multi-CPU systems target module ``03E0`` … ``03E3`` for CPU 1 … 4. * - Words per request, gap, timeout (Advanced) - Default 960 words (protocol maximum), 16 words, 2000 ms. **Addresses** in MELSEC notation. ``X``, ``Y``, ``B``, ``W``, ``SB``, ``SW``, ``DX``, ``DY`` are **hexadecimal**, all others decimal: .. list-table:: :header-rows: 1 :widths: 40 60 * - Address - Meaning * - ``D100``, ``W1A``, ``R200``, ``ZR1000``, ``SD10``, ``Z0`` - Word devices (data registers, link registers, file registers …) * - ``TN5``, ``CN3``, ``SN0`` - Current values of timers, counters, retentive timers * - ``M10``, ``X1F``, ``Y20``, ``B3``, ``L5``, ``F0``, ``SM400``, ``TS5``, ``CS3`` - Bit devices (type ``BOOL``) * - ``D100.3`` - Bit 3 of a word (bit ``0`` … ``F``) * - ``M16`` with type ``UINT`` - 16 bits of a bit device as a word (only from a multiple of 16) **Types:** ``BOOL``, ``INT``, ``UINT``, ``WORD``, ``DINT``, ``UDINT``, ``DWORD``, ``REAL``, ``LINT``, ``ULINT``, ``LWORD``, ``LREAL``. Values spanning several words occupy consecutive registers, low word first (as in GX Works). **Blocks:** start device + count (e.g. ``D100``, ``REAL``, 10 → ``D100``, ``D102`` … ``D118``). Independently of this the driver combines neighbouring addresses into as few requests as possible; bit devices are read word by word (16 bits per word). Error responses of the controller appear with their code, e.g. *SLMP error 0xC056: address out of range*; only the respective request is affected. Driver ``fins`` – Omron (FINS) ---------------------------------------------------------------------- For Omron CJ1/CJ2, CS1, CP1L/CP1H (Ethernet), CP2E and NJ/NX (with FINS enabled) via FINS/TCP or FINS/UDP, port 9600 – without an additional library. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address, port - Address of the controller or Ethernet unit; port 9600. * - Protocol - *FINS/TCP* (recommended; the controller assigns the node numbers) or *FINS/UDP*. * - Destination/source node, destination/source network (Advanced) - FINS addresses. ``0`` = automatic: with TCP from the controller, with UDP the last byte of the IP address (controller or own computer). With UDP the node table of the controller must match the address of this computer. * - Words per request (Advanced) - At most 999 (older CPUs via UDP possibly fewer). **Addresses** in Omron notation (decimal): ``D100``/``DM100``, ``W10``, ``H20``, ``A300``, ``CIO100`` (or just ``100``), extended data memory ``E0_100`` (bank 0 … 24), timer/counter present values ``T5``, ``C3``; bits with a dot and bit number 00 … 15: ``D100.05``, ``CIO0.01``, ``W3.15`` (type BOOL). DINT/REAL/LREAL occupy 2 or 4 words, low word first (as in CX-Programmer). Neighbouring addresses result in one request; blocks: start address, elements without gaps. Driver ``kvhostlink`` – KEYENCE KV (Host Link) ---------------------------------------------------------------------- For KEYENCE KV-8000, KV-7000, KV-5000/5500, KV-3000, KV Nano and KV-X with Ethernet (built-in or KV-EP21V/KV-LE21V). Protocol: Host Link (ASCII) via TCP, port **8501**. Nothing needs to be set up in KV STUDIO. No additional library. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address, port - Address of the KV; default port 8501. * - Words per request, gap, timeout (Advanced) - Default 500 words, 16 words, 2000 ms. **Addresses** in KEYENCE notation: .. list-table:: :header-rows: 1 :widths: 40 60 * - Address - Meaning * - ``DM100``, ``EM0``, ``FM0``, ``ZF10``, ``W1A`` (hex), ``TM0``, ``CM10``, ``VM0``, ``Z1`` - Word devices * - ``R1000``, ``MR500``, ``LR0``, ``CR3`` - Relays (type ``BOOL``); the last two digits are the bit number 00–15 (``R1000`` = channel 10, bit 0; ``R1015`` is followed by ``R1100``) * - ``B1F``, ``VB0`` - Link relays (hexadecimal, type ``BOOL``) * - ``T10``, ``C5`` - Current value of timer or counter (32 bit, type ``DINT``/``UDINT``) * - ``DM100.3`` - Bit 3 of a word **Types** as for the ``slmp`` driver; values spanning several words: low word first (as in KV STUDIO). Neighbouring word addresses are read with one ``RDS`` command, and so are neighbouring relays. Error responses (``E0`` invalid device number, ``E1`` invalid command …) affect only the respective request. Driver ``toyopuc`` – JTEKT TOYOPUC (Computer Link) ---------------------------------------------------------------------- For JTEKT TOYOPUC PC10G/PC10, PC3J/PC3JG, Nano 10GX and TOYOPUC-Plus with Ethernet. Protocol: Computer Link (binary) via TCP or UDP. No additional library. **Preparation (PCwin):** set up a port for *Computer Link* (TCP passive or UDP) on the Ethernet module or the built-in interface. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - IP address, port, protocol - As set in PCwin. * - Words per request, gap, timeout (Advanced) - Default 512 words, 16 words, 2000 ms. **Addresses** as in PCwin, numbers **hexadecimal**: .. list-table:: :header-rows: 1 :widths: 40 60 * - Address - Meaning * - ``D0100``, ``R0010``, ``S0020``, ``N0005``, ``B0000`` - Registers (data, link, special, current value, file registers) * - ``M0010``, ``X0007``, ``Y0020``, ``K0001``, ``L0100``, ``V0000``, ``T0005``, ``C0003``, ``P0000`` - Relays and contacts (type ``BOOL``) * - ``M010W`` - 16 relays as a word (``M0100`` … ``M010F``) * - ``D0100.F`` - Bit F of a register * - ``U00100``, ``EN0010``, ``H0000``, ``ES0000``, ``EB00000`` - Extended registers * - ``EM0010``, ``EX0007``, ``EY0007``, ``EK0000``, ``EV0000``, ``EL0000``, ``GX0000``, ``GM0000`` … - Extended relays * - ``P1-D0100``, ``P2-M1000``, ``P3-R0000`` - Program areas 1–3 (PC3J in 3-program mode, PC10); the upper number ranges (e.g. ``D3000`` … or ``M1000`` …) are also addressed this way. **Types** as for the ``slmp`` driver; values spanning several words: low word first. The word addresses of the areas correspond to JTEKT's Computer Link manual (basic area with command 1C, extended area and program areas with command 94). Driver ``s5as511`` – Siemens S5 (PG interface AS511) ---------------------------------------------------------------------- For SIMATIC S5-90U, 95U, 100U, 115U, 135U, 155U via the **PG interface** (20 mA current loop). A level converter 20 mA ⇄ RS-232 or USB is required (PG adapter cable, e.g. 6ES5 734-1BD20, or a USB PG adapter). Protocol: AS511 with 9600 baud, 8 data bits, even parity, 1 stop bit. Library: ``pyserial``. .. list-table:: Connection parameters :header-rows: 1 :widths: 30 70 * - Parameter - Meaning * - Port - Port of the adapter, e.g. ``COM1`` or ``/dev/ttyUSB0``. * - Baud rate - 9600 (standard of the PG interface). * - Parity, bytes per request, gap, timeout (Advanced) - Even parity; 64 bytes; 8 bytes; 500 ms. **Addresses** in S5 notation (German or English): .. list-table:: :header-rows: 1 :widths: 40 60 * - Address - Meaning * - ``DB10.DW4`` - Data word 4 of DB 10 (type ``WORD``, ``INT`` or ``S5TIME``) * - ``DB10.DL4``, ``DB10.DR4`` - left or right byte of data word 4 (type ``BYTE``) * - ``DB10.DD4`` - Double word from DW4 and DW5 (type ``DWORD``, ``DINT`` or ``REAL``) * - ``DB10.D4.3`` - Bit 3 of data word 4 (bit 0 … 15; type ``BOOL``) * - ``EB0``, ``EW0``, ``ED0``, ``E0.1`` (``I…``) - Inputs (process image) * - ``AB1``, ``AW2``, ``AD4``, ``A1.0`` (``Q…``) - Outputs (process image) * - ``MB10``, ``MW10``, ``MD10``, ``M5.0`` (``F…``) - Flags * - ``T5``, ``Z3`` (``C3``) - Timer or counter word **Types:** ``BOOL``, ``BYTE``, ``WORD``, ``INT``, ``DWORD``, ``DINT``, ``REAL`` (S5 floating point “KG”: exponent and mantissa in two's complement) and ``S5TIME`` (timer word with time base → milliseconds). The data in the S5 is in Motorola format (high byte first). **Sequence:** When connecting, the driver reads the system data of the CPU (location of process image, flags, timers and counters in memory), on the first access to a data block its address and length, and then reads the memory areas with as few jobs as possible. If a data block changes (reloaded, length changed), reconnect with **■ Stop** / **▶ Start**. **Notes:** * The PG interface is slow (9600 baud, handshaking): one job takes about 50–100 ms. For many values choose an interval of 1 s or more and create values as contiguously as possible. * While the logger is reading, the PG interface is occupied – stop the logger to program with STEP 5. * If a data block is missing, the variable reports “DB… does not exist”; addresses beyond the end of the DB “address outside DB…”. .. _uebernahme: Importing configurations of the single programs ====================================================================== Configuration files of the **S7 Datenlogger**, **TIA Datenlogger** and **CLX Datenlogger** are taken over – as JSON file directly with **File › Open…**, as older INI file after the one-time conversion (**File › Convert INI file …**, see `Converting older INI files `__). The following applies: * The driver of each controller is recognized from its entries: ``rack``/``slot`` → ``s7``, ``pfad``/``cpu`` → ``clx``, ``tls``/``rolle``/``port`` → ``tia``. * S7 variables (``bereich``, ``db``, ``byte``, ``bit``) are converted into addresses, e.g. ``DB10.DBD4`` or ``M5.0``; S7 blocks get their start address. Tag names of TIA and CLX are taken over unchanged. * The paths of the S7 DB sources (``symbolquellen``) move to ``treiberdaten``. * Charts, axes, formulas, blocks, triggers, PID settings, database, web server and display are taken over unchanged. Saving uses the format of the PLC Datenlogger (keys ``treiber`` and ``adresse``). The single programs can **no longer** read this file afterwards – so save with **Save as…** under a new name if the file is still to be used in the single program. Configurations of several single programs can be merged by creating the controllers and variables again in the configuration program or by copying the entries of the lists ``steuerungen`` and ``variablen`` in the JSON file by hand (adapt ``steuerung`` of the variables). Logger (``plc_logger.py``) ====================================================================== Controls ---------------------------------------------------------------------- .. figure:: images/en/logger_hauptfenster.png :alt: Main window of the logger :width: 90% :align: center The main window of the logger with toolbar, charts, value table and status bar. Toolbar (top): .. list-table:: :header-rows: 1 :widths: 25 75 * - Element - Function * - **▶ Start / ■ Stop** - Starts or ends recording and CSV logging. * - **Online / Offline** - Switches between continuous display and review. * - **Load CSV** - Opens saved CSV files for viewing (offline mode). * - **Config editor** - Starts the configuration program. * - **Value display** - Shows or hides the value table (right). * - **Bars** - Shows or hides the narrow bars next to the charts. * - **Y auto** - Active: all Y axes are scaled automatically and override fixed ranges. Inactive: the settings of the configuration apply. * - **Bool in chart** - Additionally draws BOOL variables as a filled step line in the chart (depending on the Y axis). Default: off, BOOLs appear only as strips in the legend. * - **Reset rulers** - Sets the two rulers (offline) to one third and two thirds of the visible time range. * - **Demo** - Simulated values instead of a PLC (see `Demo mode `__). * - **Zoom rectangle** - Active: drag a region with the left mouse button; time and values of this chart are enlarged to it (see `Zooming and time axes `__). * - **Align time axes** - All charts show the time range of the chart used last again. * - **Reset zoom** - Scale the Y axes as configured again and align the time axes. * - **Screenshot** - Opens a list of the charts; the chosen chart is saved as PNG or SVG (see `Screenshots of charts `__). * - **Window [s]** - Width of the visible time window in seconds (1 to 604800). At the bottom of the window is the **time scroll bar** (active only in offline mode). The status line shows connection messages and the path of the saved CSV file. The **View** menu contains the layout of the charts, a list for showing and hiding single charts and the switches for value display, values at the mouse pointer, trigger marks and bars. The **Analysis** menu contains XY chart, frequency analysis, PDF report and PID tuning. Starting and stopping the recording ---------------------------------------------------------------------- #. Press **▶ Start**. The logger reloads the configuration, builds the charts and connects to the controllers. #. Each controller is read at its own interval. The measurements are merged into rows and written to the CSV file. #. **■ Stop** ends the recording and closes the file. When the program is closed, it stops automatically and – if the option is set – archives the current CSV file (see `Limiting the file size and archiving `__). If the connection is lost, the logger tries to restore it by itself and reports this in the status line. During the interruption there are gaps in the data – only for the variables of the affected controller; the others continue. Reading, calculating the formulas and writing the CSV file run in separate threads, independent of the user interface. The display fetches a section of the data only about ten times per second and does not redraw invisible curves; this keeps operation smooth even with many variables. **File** menu of the logger: **Load config …** (``Ctrl+O``, file dialog for a configuration file with any name), **Reload configuration** (``F5``), **Config editor**, **Connect to logger (client) …** (``Ctrl+K``, `Logger as client`_), **Load CSV**, **Join CSV files and save …**, **Load from database …**, **Export values (CSV/Excel) …**, **Web server address …**, **Event log …**, **Note to the event log …** and **Exit**. The window title shows the project name and the configuration file. .. _status-led: Status LEDs of the connections ---------------------------------------------------------------------- .. figure:: images/en/status_leds.png :alt: Status LEDs :width: 70% :align: center Status LEDs in the status bar: green, yellow, red, grey. In the status bar an **LED** with the controller's name shows the connection state of each controller: .. list-table:: :header-rows: 1 :widths: 20 80 * - Colour - Meaning * - grey - Controller not active (disabled or recording stopped). * - yellow - Connection is being established. * - green - Connected, reading. * - red - Connection or read error; the logger tries again. The LED's tooltip shows the status message (for errors the error text) and the cycle time of the last read request. The web server shows the same LEDs. Online mode ---------------------------------------------------------------------- .. figure:: images/en/logger_online.png :alt: Online mode :width: 90% :align: center Online mode: continuous display of the last seconds. In online mode the time axis follows the newest data. The last *N* seconds are always shown (setting **Window [s]**). The value table shows the latest measurement in the column *Current*. The recording continues independently of the display. **Values at the mouse pointer:** When the mouse is over a chart, a dashed vertical line appears at the nearest measurement. A box next to it shows its time and the values of all visible variables of this chart (including BOOL variables); dots mark the values on the curves. If the mouse stays still, line and values move along with the new measurements. When the mouse leaves the chart, the display disappears. To switch off: **View › Values at mouse pointer (online)** (the setting is remembered). In offline mode the rulers take over this task. **Zooming with the mouse:** In online mode, too, the time axis of a chart can be zoomed with the **mouse wheel** (or by dragging with the right mouse button); the new width applies to this chart only, the right end keeps following the newest values. More under `Zooming and time axes `__. .. _zoomen: **Zooming and time axes** (online and offline): * The **mouse wheel**, dragging with the mouse and the zoom rectangle only affect the **chart under the mouse pointer**. So each chart can show a different time range, e.g. one hour at the top and a few seconds below. * **Zoom rectangle** (toolbar, toggle): drag a region with the left mouse button – the time axis and all Y axes of the chart are enlarged to it. When it is off, the left mouse button moves the time axis. * **Align time axes:** all charts take over the range of the chart used last. A new entry in **Window [s]** aligns them as well. * **Reset zoom:** Y axes as configured again (or *Y auto*) and time axes aligned. * **Window [s]** and the scroll bar show the range of the chart used last. The scroll bar moves all charts together; each keeps its width. Offline mode ---------------------------------------------------------------------- .. figure:: images/en/logger_offline.png :alt: Offline mode :width: 90% :align: center Offline mode: review with scroll bar. In offline mode the display is frozen and you can go back in time: * **Time scroll bar** at the bottom: scroll through the recorded data. * **Mouse:** drag in the chart with the mouse button pressed to move the time axis, and zoom with the mouse wheel – each only in this chart (see `Zooming and time axes `__). Scroll bar and *Window [s]* follow automatically. * **Window [s]:** width of the visible time range. .. note:: When switching to offline mode, a snapshot of all data measured so far is taken. If the recording continues, newer data only appears when you switch from *Online* to *Offline* again. The memory in the program is limited to about 300,000 data points; older points are then removed from the display. The CSV file always contains all data. Rulers (offline) ---------------------------------------------------------------------- .. figure:: images/en/logger_lineale.png :alt: Rulers in offline mode :width: 90% :align: center Two rulers with time and difference display. In offline mode two vertical rulers appear in all charts: **L1** (yellow) and **L2** (cyan). Both can be moved with the mouse and are synchronized across all charts. The value table then shows: .. list-table:: :header-rows: 1 :widths: 25 75 * - Column - Content * - Ruler 1 - Value of each variable at the time of L1. * - Ruler 2 - Value of each variable at the time of L2. * - Δ (L2 − L1) - Difference of the two values. * - Minimum, Maximum, Mean, Std. dev. - Statistics of all measurements between the two rulers. Above the table the times of L1 and L2 and the time difference **Δt** in seconds are shown. The nearest measurement in time is used (no interpolation). .. _trigger-marken: Trigger marks on the time axis ---------------------------------------------------------------------- .. figure:: images/en/trigger_marken.png :alt: Trigger marks :width: 90% :align: center Trigger marks: alarm (red), warning (orange), recording by trigger (green), note (grey). Events from the event log appear in all charts as a **vertical dashed line** with a short text at the bottom of the time axis (▲ name of the trigger): red = *Alarm*, orange = *Warning*, blue = *Info*, green = start of a `recording by trigger `__, grey = note. The tooltip shows time, text and the times of going and acknowledgement. The marks are shown online and offline, also when displaying a loaded CSV file or a database time range (from the event log of the configuration). With very many events in the visible range at most 150 are shown. To switch off: **View › Trigger marks on the time axis**. .. _seiten: Pages, charts and layout ---------------------------------------------------------------------- .. figure:: images/en/anordnung_raster.png :alt: Charts in a grid :width: 90% :align: center Charts of one page arranged as a grid. The charts are placed on **pages**. A page is a dock window or a tab and can contain **several charts**: * Without page entries in the configuration, all charts are on one common page *Charts*. In *Tabs* mode each chart then gets its own tab. * With the field **Page (tab)** in the configuration you decide yourself which charts share a page (same page name = same page). This way you can create e.g. the tabs *Process* and *Alarms* with several charts each. **Minimum height and scroll bar:** Each chart has a minimum height. If not all charts of a page fit into the window, a scroll bar appears on the page. In *Side by side* mode a minimum width with a horizontal scroll bar applies accordingly. **Layout of the pages** (menu **View › Layout**): .. list-table:: :header-rows: 1 :widths: 25 75 * - Mode - Effect * - Stacked - Pages lie one above the other; the charts of a page are stacked. * - Side by side - Pages lie side by side; the charts of a page are also side by side. * - Tabs - Each page is a tab; the charts of a page are stacked. **Layout of the charts on a page** (menu **View › Charts on the page**): *Automatic* follows the layout of the pages; *Stacked* and *Side by side* force one column or one row; **Grid** arranges the charts in rows and columns. The number of columns is set with **View › Grid columns** (*Automatic* chooses about the square root of the number of charts, i.e. three columns for six charts). A last single chart fills the remaining row. The default is set in the configuration (tab *Display*). The layout can be adjusted further by **drag & drop**: * **Pages:** grab the title bar of a page and drag it to the edge of another page (next to or above it) or onto its centre (as tab). Double-clicking the title bar detaches the page as a floating window. * **Charts within a page:** grab the title line of a chart (bold, above the chart) and drag it onto the title line of another chart on the same page. The chart is inserted at that position. Pages can be hidden and shown again via **View › Pages / charts**. The page layout adjusted by drag & drop is kept when starting again within the same program session, as long as the page names and the mode stay the same. After restarting the program the default layout applies again. All charts share the same time axis. Legend with live values ---------------------------------------------------------------------- .. figure:: images/en/legende.png :alt: Legend :width: 90% :align: center Legend with live values; one curve is highlighted, one hidden. The legend in each chart shows the **current value** after the name of each variable, in the variable's colour, e.g. ``Temperature: 51.234``. Online this is the latest measurement, offline the value at ruler 1. **Highlighting a curve:** a **left click** on the name (or sample) of a curve in the legend highlights it: the curve is drawn thicker and in the foreground, the name appears in **bold**, all other curves of the chart are dimmed. Clicking the same name again removes the highlighting; clicking another name moves it. **Hiding and showing a curve:** right-clicking the name of a curve in the legend opens a menu with *Hide curve* or *Show curve* and *Show all curves of this chart*. Hidden curves appear grey in the legend with the addition *(off)*. The tick in the value table stays in sync. The choice is kept when the layout changes. .. _screenshots: Screenshots of charts ---------------------------------------------------------------------- .. figure:: images/en/screenshot_menue.png :alt: Screenshot menu :width: 70% :align: center Menu “Screenshot” with choice of chart and light background. Single charts can be saved as an image: #. Click **Screenshot** in the toolbar (or in the **Screenshot** menu) and choose the chart. #. In the save dialog choose file name and format: **PNG** (bitmap) or **SVG** (vector graphic). The format results from the file extension or the chosen file type. The screenshot contains the chart exactly as displayed: curves, all Y axes, legend, bars and, in offline mode, the rulers. PNG files are created with double resolution. The **SVG file** is drawn from the measurement data itself (axes with ticks, grid, time axis, curves, BOOL traces, rulers with labels and legend with values) and can be scaled without loss and edited further, e.g. in Inkscape or office programs. If the chart is in a hidden tab, it is brought to the front automatically. For reports and printouts, the option **Light background (for reports/printing)** can be switched on in the **Screenshot** menu. The screenshot is then saved with a white background and dark text; rulers are drawn in darker colours. The screen display itself stays unchanged. The setting applies to the current program session. Value table (value display) ---------------------------------------------------------------------- .. figure:: images/en/wertetabelle.png :alt: Value table :width: 90% :align: center Value table with current values (online) or ruler values (offline). The table on the right lists all variables for which *value display* is enabled in the configuration. * The name is shown in the variable's colour. Hovering over the name shows the address (for calculated variables the formula). * With the **tick** in front of the name you hide or show the variable's curve in the chart (alternatively by right-clicking in the legend). * The columns change with the mode (*Current* online, *Ruler 1 / Ruler 2 / Δ* offline). * Offline the table also shows the **statistics between the rulers**: *Minimum*, *Maximum*, *Mean* and *Std. dev.* (sample standard deviation, like ``STDEV`` in Excel). All data points from the one at ruler 1 to the one at ruler 2 (inclusive) are taken into account; missing values are skipped. For BOOL variables the mean is the share of time the signal was on (0.25 = 25 %). The values follow every movement of the rulers. Y axes and scaling ---------------------------------------------------------------------- * Each Y axis is labelled in the colour of its first variable. * Axes with **auto scaling** adapt to the data visible in the time window. Axes with fixed limits keep their range. * The **Y auto** switch in the toolbar temporarily overrides all fixed ranges. When it is switched off again, the settings of the configuration apply. Bars for current values ---------------------------------------------------------------------- Next to each chart a narrow bar per variable shows the current value (width adjustable: configuration › Display › *Bar width*). The scaling corresponds to the variable's Y axis. In offline mode the bars show the values at ruler 1. Move the mouse over the bars to see names and values as tooltip. BOOL variables ---------------------------------------------------------------------- .. figure:: images/en/bool_signale.png :alt: BOOL signals :width: 90% :align: center BOOL signals: line at 0, upward strip at 1, next to the legend rows. Boolean variables are displayed independently of the Y axes: * **In the legend** name and value are listed one below the other like the analogue curves. Next to each BOOL entry, at the height of its legend row, a **line** on the base line (value 0) or an **upward strip** (value 1) in the variable's colour runs across the **width of the chart**, like a digital signal. Like a curve it covers the displayed time range (online the last *N* seconds, offline the visible section). This way several BOOL variables can be compared at a glance without covering the chart. * **As a curve** BOOLs are not drawn by default (they would otherwise depend on a Y axis). With **Bool in chart** in the toolbar they additionally appear as a transparently filled step line. * **In the value table** the cell is **filled** in the variable's colour for value 1 and empty for value 0. Hidden BOOLs (right click in the legend) and highlighted BOOLs (left click) are dimmed or drawn with a thicker strip. The SVG export and the web server (where the name is shown in the row of the strip) show the BOOL signals in the same way. .. _demo-modus: Demo mode ====================================================================== Demo mode creates simulated values without a PLC being connected: #. Activate **Demo** in the toolbar. #. Press **▶ Start**. The variables of your configuration are supplied with test signals (REAL: sine with noise, BOOL: square wave, integers: sawtooth). If nothing is configured yet, demo mode creates example charts with several Y axes, a BOOL signal and a control loop for the PID tuning. The switch is locked during recording and is not saved. The demo data is stored as ``demo_YYYYMMDD_HHMMSS.csv``. .. _webserver: Web server (charts in the browser) ====================================================================== .. figure:: images/en/web_tablet.png :alt: Web page on a tablet :width: 90% :align: center The charts in the browser of a tablet. With the option **Start web server** (tab *Web server & headless*) the logger provides the charts as a web page. It can be opened with any browser in the network, e.g. on a tablet or smartphone – also in headless operation. * **Address:** ``http://:/`` (default port 8080). The logger shows the address under **File › Web server address …** – together with a **QR code**: scan it with the smartphone camera instead of typing (with the access code if no login is set up). It is also written to the log at startup. The firewall may have to allow the port. * **Access code:** If a code is entered in the tab, the page is opened with ``http://…:8080/?token=CODE``. Without code and without login anybody in the network can watch. There are no control functions; with write access events can be acknowledged, notes entered and the process view edited (see `HTTPS and login`_). * **HTTPS and login:** see below. * **Process view:** tiles with values, gauges and lamps under ``/prozess``, see `Process view`_. * **Logos:** customer logo and logo of the configuration (tab *Display*) appear in the header of the pages (charts, process view, login); empty fields = no logo. * **Language:** the pages (charts, login, process view, IO check) appear in the language set in the program (menu *Language*), e.g. English. * **Display:** The page shows the charts per page (tab) with Chart.js, with several Y axes, BOOL signals as step lines and status LEDs of the controllers. The display adapts to the screen size. * **Operation:** *Live* shows the latest time window; **◀ ▶** pages back in time (history), **Pause** stops the display. Tapping a legend entry highlights a curve, a long press or double-click hides it. Zoom, rulers, history from the database, export and events: see `Analysing in the browser`_. * **Full screen:** The button at the top right of a chart (or a double-click into the chart) enlarges it to the whole window; the header with time window, **◀ ▶**, *Live* and *Pause* stays visible and usable. Where the browser allows it, it also switches to real full screen (without address bar). Back to the normal display: the same button, double-click, ``Esc`` or the browser's back button or gesture. In full screen more points are loaded (to match the width). * **Chart.js:** The library is served from ``web_static/chart.umd.js`` (the installer contains it). If the file is missing, the browser loads it from the internet instead (jsdelivr); in a closed network put the file ``chart.umd.js`` (Chart.js 4) into the folder ``web_static`` manually. .. figure:: images/en/webserver_qr.png :alt: Web server address with QR code :width: 70% :align: center File › Web server address …: address with QR code for scanning. The server transfers only the visible data, reduced to the screen width (minimum and maximum per section are kept), and compresses it. .. _web-auswerten: Analysing in the browser ---------------------------------------------------------------------- The web page offers the most important analyses of the logger – on PC, tablet or smartphone, without installation. One logger records (e.g. headless on a Raspberry Pi), any number of browsers show the same data. * **Zoom:** The **mouse wheel** over a chart (or **two fingers** on a tablet) stretches or compresses the time axis of this chart, two fingers also move it. **Dragging a range** with the mouse zooms to the chosen section – dragging vertically as well zooms the Y axes too. The chart then has an **own time axis** (note above the chart) and no longer follows *Live*. **⇔ Align** applies the time range of the selected chart (blue frame) to all, **⟲ Zoom** resets all charts (live, Y axes as configured). * **Rulers:** **┆ Rulers** shows two vertical rulers and pauses the display. Dragging a ruler or clicking/tapping into the chart sets the nearer ruler. The legend shows the values at ruler 1 and 2 and the difference per variable, the line below the buttons both points in time and the distance. * **History from the database:** The logger keeps the latest values in memory (up to 300,000 rows). If a database is configured, the server fetches older periods from there – with **◀**, the time window up to **7 days** or the **date/time** field (jumps to this point in time). The header then shows *Database*. Long periods are read as averages; the browser needs no access to the database. Gaps (logger stopped) stay open in the chart. * **Export:** **⇩ Export** saves the values of the displayed time range, between the rulers or of a free period as an **Excel** or **CSV** file (raw data, also from the database), optionally only the displayed curves. **PDF report** creates the report for the same period as in the logger (statistics, charts, events). * **Events:** **🔔 Events** (or a click on the red *open* badge) lists events and notes of the last day up to year, optionally only open ones. **⌖** jumps to the point in the chart (ruler 1 at that time). With write access: **✓ Acknowledge** (single or all) and **✎ Note …** (at the time of ruler 1, otherwise now); the acknowledgement records the logged-in user. Events and notes appear as dashed marks in the charts. .. figure:: images/en/web_lineale.png :alt: Rulers in the browser :width: 95% :align: center Rulers: values at both points in time and difference in the legend, event marks (dashed). .. figure:: images/en/web_ereignisse.png :alt: Event list in the browser :width: 80% :align: center Events and notes: ⌖ jumps into the chart, acknowledging with write access. .. figure:: images/en/web_export.png :alt: Export in the browser :width: 80% :align: center Export of the time range as Excel/CSV or PDF report. .. _https-anmeldung: HTTPS and login ---------------------------------------------------------------------- .. figure:: images/en/web_anmeldung.png :alt: Login page of the web server (smartphone) :width: 45% :align: center Login page of the web server (smartphone). **HTTPS** (tab *Web server & headless*, *HTTPS (encrypted)*): the page is then reachable at ``https://:/``. Without a certificate of your own, the logger creates a **self-signed** one at the first start (RSA 2048, valid for ten years, for computer name, IP address and ``localhost``; folder ``web_tls`` in the data folder). The browser warns on the first visit because it does not know the issuer: compare the fingerprint and confirm the exception. The **SHA-256 fingerprint** is shown under **File › Web server address …** (in headless operation it is in the log file). With a certificate of the company CA (enter PEM files for certificate and key) there is no warning. Requires the package ``cryptography`` (included in the installation). .. figure:: images/en/web_benutzer.png :alt: Creating web server users (configuration program, tab Web server & headless) :width: 60% :align: center Creating web server users (configuration program, tab Web server & headless). **Login:** Create users with **Users …** (name and password, at least 8 characters); only a hash of the password (PBKDF2-SHA256) is stored, not the password itself. If at least one user is configured, the browser first shows a login page; the login is valid for 12 hours or until **⎋ Log out** (top right of the page). After five failed attempts the address is blocked for one minute. An additionally configured access code still allows access without login (``?token=CODE``, e.g. for a permanently installed display). **Write access:** The tick in front of the user name grants write access – acknowledge events, enter notes, edit the process view. Without the tick the user may only view and export. New users initially have no write access; users from older configurations keep it. Once users are set up, the access code alone only grants read access; without users, anybody with access may write. Next to **Users …**, ✎ marks the users with write access. .. note:: Without HTTPS, passwords and measurements are transmitted unencrypted. Therefore use login together with HTTPS. For access from the internet, the server should also be behind a VPN or a reverse proxy. .. _prozessbild: Process view ---------------------------------------------------------------------- .. figure:: images/en/prozessbild.png :alt: Process view in the browser :width: 95% :align: center Process view: text, gauges, numeric values (pressure above the warning limit), status lamp, bars and short trend. Besides the charts the web server offers a **process view** – an overview with large, easily readable tiles, e.g. for a monitor in the control room or a tablet at the machine. Open it with ``http://:/prozess``, the link **Prozessbild** at the top of the chart page or in the logger with **File › Process view in the browser** (opens the default browser of this computer). The web pages are in German. Tile types: * **Zahlenwert** (numeric value) – large value with unit. * **Zeigerinstrument** (gauge) – arc from minimum to maximum, warning and alarm ranges in colour. * **Balken** (bar) – horizontal or (for a tall, narrow tile) vertical, e.g. a level. * **Zustand (Lampe)** (status lamp) – for BOOL signals: lamp with texts and colours for ON and OFF (optionally inverted). * **Kurzverlauf** (short trend) – line of the last seconds to hours (*Zeitraum*) with the current value. * **Text / Überschrift** (text / heading) – e.g. a plant section or a note. For value, gauge, bar and trend, **upper and lower warning and alarm limits** can be entered: if one is exceeded, the tile turns yellow or red. Without a measurement (connection lost) **—** is shown. Several **pages** appear as tabs at the top. On a smartphone the tiles are stacked (two per row or a full row). .. figure:: images/en/prozessbild_bearbeiten.png :alt: Editing the process view :width: 95% :align: center Editing: tile selected (blue), its properties on the right. **Editing:** button **✎ Bearbeiten** (on a PC or tablet). Dragging a tile with the mouse moves it on the grid (12 columns), the bottom right corner changes its size; the arrow keys move the selected tile, with ``Shift`` they change its size, ``Del`` deletes it. The properties of the selected tile are on the right (type, variable, title, unit, decimals, minimum/maximum, limits, colours, texts). **+ Kachel** (add tile), **Kopie** (copy), **Löschen** (delete), pages are added, deleted and renamed with **+**/**−**; **Vorschlag** (suggestion) fills the page with one tile per variable. **Speichern** (save) stores the layout, **Abbrechen** (cancel) discards the changes. * The layout is stored in the file ``.prozessbild.json`` next to the configuration file (e.g. ``plant.prozessbild.json``); the configuration program does not change it. Tiles refer to the **name** of a variable – if a variable is renamed, the tile shows "Variable fehlt" (variable missing) and has to be assigned again. * Without a saved layout the page shows a suggestion (BOOL as lamp, otherwise value). * **Who may edit:** if users are set up (`HTTPS and login`_), only logged-in users with write access – whoever opens the page with the access code only can view it but not change it (good for a permanently installed display). Without login anybody with access to the page may edit. .. _logger-client: Logger as client ---------------------------------------------------------------------- A logger can display the recording of **another** logger – for example a Raspberry Pi recording headless at the plant while a second logger in the office only displays and analyses. The client needs **no configuration of its own** and no connection to the PLC: charts, variables, page layout, window width and the names of the PLCs come from the recording logger, as do the values. On the server only the web server has to be enabled (`Web server (charts in the browser)`_). **Connecting** * in the start window *Connect to logger …*, * in the logger *File › Connect to logger (client) …* (Ctrl+K) or * from the command line ``plc_logger.py --client https://logger-kessel:8080/ --benutzer chef`` (without an address only the dialog appears). The dialog asks for the **address** (``http://`` or ``https://``, host name or IP address and port of the web server), **user** and **password** – or, without users set up, the **access code**. Address and user are remembered for next time, the password never. If the server uses a self-signed certificate, the client shows its **SHA-256 fingerprint**; compare it with *File › Web server address …* on the server (headless: log file). Once confirmed, the client remembers the certificate; if it changes later, the client refuses to connect. **In the client** * The display runs live (the client fetches the new rows at the refresh rate of the web server); on connecting, the last 30,000 rows come from the server's memory. Offline view, rulers, zoom, value table, analysis (XY, FFT, PID), report, screenshots and *Export values* work as when recording yourself. * *Load from database …* and *Show in chart* (events) fetch older periods from the server – from its memory, before that from its database (long periods as averages). Back to the live display with *Online*. * The status LEDs show the state of the PLCs **on the server**; if the server cannot be reached they turn red and the client keeps trying. * **Events:** counter, event log and marks come from the server. Acknowledging and notes go to the server – only for users with write access (`HTTPS and login`_). * If the server starts a new recording (e.g. with a changed configuration), the client reconnects on its own and rebuilds the display. * *▶ Connect* / *■ Disconnect* replace start/stop. Not available are demo, configuration editor, IO check, web server and process view of the client – they belong to the recording logger. *File › Disconnect (own configuration)* or *Load config …* return to your own configuration. * The client writes no CSV files and nothing to the database; so there is only one recording and one data basis. .. _opcua-server: OPC UA server ====================================================================== The logger can provide its values itself as an **OPC UA server** – for a control system, MES, SCADA, Node-RED or another logger. This way, e.g. values from an S5 or a Modbus controller that cannot do OPC UA itself, and the calculated variables, can be used in an OPC UA network. The server is **read-only**. **Enable:** configuration program, tab *Web server & headless*, **OPC UA …**: * **Start OPC UA server** – the server runs as long as recording runs (also in headless operation); at start the endpoint is shown in the status bar or the log. * **Address (host)** and **port** (default 4840). Endpoint: ``opc.tcp://:4840/plc-datenlogger/``. The firewall must allow the port. * **Update** – how often changed values are taken over into the server (default 500 ms; faster than the sampling time of the controllers is pointless). * **Security** – one or more levels: *None*, *Basic256Sha256* (sign or sign and encrypt), *Aes128Sha256RsaOaep*, *Aes256Sha256RsaPss*. For the encrypted endpoints the logger creates a self-signed certificate at the first start (folder ``opcua`` in the data folder, ``server_cert.der``); the client may have to accept it as trusted. Own certificate: enter the files. * **Access** – *Anonymous* and/or *Login with the web server users* (the same names and passwords as in `HTTPS and login`_). For a login an encrypted endpoint should be enabled, otherwise the password travels across the network in plain text. .. figure:: images/en/opcua_server.png :alt: OPC UA server dialog :width: 55% :align: center OPC UA server dialog: endpoint, security levels and access. **Address space** (namespace ``urn:plc-datenlogger``): .. code-block:: text Objects └─ PLC Datenlogger ├─ PLC 1 one folder per controller with its variables │ ├─ Temperature ns=2;s=Temperature (Double; BOOL variables: Boolean) │ └─ … ├─ Calculated calculated variables (formulas) ├─ Events per trigger: Boolean, True while the event is active └─ Status ├─ PLC 1 Boolean: connection OK ├─ PLC 1_Text status text of the connection ├─ Timestamp time of the last measurement row └─ Recording True while recording runs The NodeId of a variable is its name (``ns=;s=``; the client gets the index via the namespace ``urn:plc-datenlogger``, usually 2). The folders *Calculated*, *Events*, *Timestamp* and *Recording* are named in the language of the interface; their NodeIds do not change. The **source timestamp** is the time of the measurement. If a variable has no value (controller not reachable), it has the status **BadNoCommunication**. Clients can read or subscribe to the values; only changes are reported. .. _headless: Headless operation (recording only) ====================================================================== Without user interface the logger only records: reading from the controllers, formulas, CSV file, archiving, trigger recording, reports and – if enabled – web server. This saves resources and is suitable for continuous operation, e.g. as autostart program on an industrial PC. * **Switching on:** option *Headless mode* in the tab *Web server & headless* of the configuration, or command-line parameter ``--headless``. With ``--gui`` the user interface can be opened despite the headless mode being set. On Linux without a graphical session (systemd service, SSH) the logger always starts headless, even if the option is off. * **Messages** (connection, errors, archiving) are written to the log file ``plc_logger.log`` in the program or data folder (rotating, several files). * **Exiting:** ``Ctrl+C`` in the console window or the signal SIGTERM (stop service, Windows: close the window) exits cleanly: the CSV file is closed and – if the option is set – archived. * **Stopping from the configuration program:** **File › Show/stop headless loggers …** or **Running loggers …** in the tab *Web server & headless* lists the running headless loggers (project, configuration, start time, computer, process ID, web server). **Stop logger** ends the selected one as cleanly as SIGTERM, within about one second – also on Windows and when the logger was started without a console. For this, every headless logger registers in the folder ``laufend`` of the data folder; so the loggers shown are those running with the same data folder (same user or same portable folder). A logger running as a service under another user does not appear here; if a service restarts the logger automatically, stop the service itself (e.g. ``sudo systemctl stop ``). * The installed version contains the shortcut *PLC Datenlogger (Headless, nur Aufzeichnung)* in the start menu. .. figure:: images/en/headless_beenden.png :alt: Showing and stopping running headless loggers :width: 95% :align: center Running headless loggers in the configuration program. .. _datenbank: Database recording ====================================================================== The measurements can be written to a database **in addition to or instead of** the CSV file – e.g. for evaluation with SQL or display in Grafana. The settings are in the configuration program in the tab **Database**; the CSV file is switched on or off with the tick **Write CSV file** in the tab *Recording*. .. list-table:: :header-rows: 1 :widths: 25 75 * - Field - Meaning * - Database - *None*, *SQLite (file)*, *MariaDB / MySQL*, *TimescaleDB / PostgreSQL*, *QuestDB*, *InfluxDB 3 Core*, *VictoriaMetrics* or *Prometheus (remote write)*. * - Server / port - Host name or IP address of the database server; port *default* = 3306 (MariaDB), 5432 (PostgreSQL/TimescaleDB), 9000 (QuestDB), 8181 (InfluxDB 3) or 8428 (VictoriaMetrics) or 9090 (Prometheus). For QuestDB, InfluxDB, VictoriaMetrics and Prometheus a complete URL may also be entered here, e.g. ``https://server:8181`` (encrypted; the port field then does not apply). * - Database name - Name of the database on the server. MariaDB/PostgreSQL: it must already exist, the program creates the table itself. InfluxDB 3: created if needed. Not relevant for QuestDB, VictoriaMetrics and Prometheus (one database per server). * - User / password - Access data. The user needs the rights CREATE (at the first start) and INSERT. The password is stored in plain text in the configuration file. QuestDB, InfluxDB, VictoriaMetrics and Prometheus: user and password are sent with HTTP basic authentication; **without user the password is used as token** (InfluxDB 3: token ``apiv3_…``, QuestDB Enterprise, VictoriaMetrics behind *vmauth*, Prometheus behind a proxy); both empty = no authentication. * - SQLite file - File name of the SQLite database; a relative path refers to the data folder of the program. * - Table - Name of the table (default ``messwerte``; letters, digits, ``_``). VictoriaMetrics and Prometheus: the metric is called *table* + ``_wert``, i.e. ``messwerte_wert``. * - Write changes only - A value is only written if it has changed, but at least every minute. Saves a lot of space for slowly changing values. * - Also write events and notes - Additionally write trigger events and notes to the database (default: on, see *Events in the database* below). * - Delete after, Use at most - Delete old values automatically (see `Cleaning up old recordings `__): after *n days* (SQLite, MariaDB, PostgreSQL/TimescaleDB, QuestDB) or when the values take up more than *n MB* (SQLite only). * - Test database - Connects, creates the table and reports the result. * - Storage … - Shows the space used by the table and the whole database and the number of values. SQLite: file size, table, exact count. MariaDB and PostgreSQL/TimescaleDB: table and database, count estimated. QuestDB (from 8.2) and InfluxDB 3: table and count (InfluxDB without the values of the last minutes). Prometheus: only the whole database. **VictoriaMetrics:** whole database (space, values, bytes per value, retention, free space), the metric per project (values, variables, oldest value), the growth of the last 24 hours and the space needed at full retention estimated from it. .. figure:: images/en/speicherplatz.png :alt: Storage of a VictoriaMetrics database :width: 50% :align: center **Storage …** with VictoriaMetrics: whole database, per project and space needed. **Table structure** (one row per value, “narrow” format): .. list-table:: :header-rows: 1 :widths: 20 30 50 * - Column - Type - Content * - ``zeit`` - SQLite: text, MariaDB: ``DATETIME(3)``, PostgreSQL: ``TIMESTAMPTZ``, QuestDB: ``TIMESTAMP`` (designated timestamp) - Time of the measurement in **UTC** with milliseconds * - ``projekt`` - Text (QuestDB: ``SYMBOL``) - Project name from the configuration (several loggers can share a table) * - ``variable`` - Text (QuestDB: ``SYMBOL``) - Name of the variable * - ``wert`` - Floating point number - Measured value (BOOL as 0/1) Invalid values (e.g. during a connection failure) are not written. An index on ``variable, zeit`` speeds up queries of single variables. With **TimescaleDB** the table automatically becomes a *hypertable* (partitioned by time); if the extension is not installed, a normal PostgreSQL table is created and the status line reports this. **QuestDB** is addressed via its HTTP interface (default port 9000, the same port as the web console): the values are sent in *InfluxDB Line Protocol* to ``/write``, read-mode queries to ``/exp``. The table is created partitioned by day; from QuestDB 7.3 with deduplication on ``zeit, projekt, variable`` – a batch sent again after a failure thus does not create duplicate rows (older versions: without deduplication, the status line reports this). An empty project name is stored as ``NULL``. **InfluxDB 3** (Core or Enterprise) is also addressed via HTTP (default port 8181): values in line protocol to ``/api/v3/write_lp``, queries with SQL to ``/api/v3/query_sql``. The program creates database and table (tags ``projekt`` and ``variable``, field ``wert``); in InfluxDB the time column is called ``time`` instead of ``zeit``. The same variable at the same time overwrites itself, so no duplicate rows arise. If authentication is enabled (default in InfluxDB 3), enter the token (``influxdb3 create token --admin``) in the field *Password* and leave *User* empty. **VictoriaMetrics** stores time series instead of tables: each variable becomes a series of the metric ``messwerte_wert`` with the labels ``projekt`` and ``variable``. Writing uses line protocol to ``/write``, reading the Prometheus interface (read mode: raw data via ``/api/v1/export``, averages via ``/api/v1/query_range``). VictoriaMetrics stores timestamps with milliseconds and by default keeps data for one month only (command-line parameter ``-retentionPeriod``). **Prometheus** stores time series like VictoriaMetrics (metric ``messwerte_wert``, labels ``projekt`` and ``variable``). Writing uses **remote write** (``/api/v1/write``, protobuf with snappy compression, no additional library); Prometheus must be started with ``--web.enable-remote-write-receiver`` for this, otherwise the status line reports “Remote write is not enabled”. Reading uses the HTTP interface (read mode: raw data hour by hour via ``/api/v1/query``, averages via ``/api/v1/query_range``; first and last time in the overview are accurate to about 1/2000 of the retention period). Prometheus only accepts values per series in chronological order and at most about one hour old. It rejects older values (e.g. written after a long outage); the logger discards such batches, reports them (“… values rejected”) and counts them in the tooltip of the database LED. Remedy: ``storage: tsdb: out_of_order_time_window: 1d`` in the Prometheus configuration. The retention period is set with the command-line parameter ``--storage.tsdb.retention.time`` (default 15 days). Example queries: .. code-block:: sql -- Trend of a variable in the last hour (PostgreSQL/TimescaleDB) SELECT zeit, wert FROM messwerte WHERE variable = 'Temperatur' AND zeit > now() - interval '1 hour' ORDER BY zeit; -- Minute averages (TimescaleDB) SELECT time_bucket('1 minute', zeit) AS minute, avg(wert) FROM messwerte WHERE variable = 'Temperatur' GROUP BY minute ORDER BY minute; -- Latest values of all variables (MariaDB / SQLite) SELECT variable, MAX(zeit) FROM messwerte GROUP BY variable; -- Minute averages (QuestDB) SELECT zeit, avg(wert) FROM messwerte WHERE variable = 'Temperatur' SAMPLE BY 1m; -- Latest value per variable (QuestDB) SELECT * FROM messwerte LATEST ON zeit PARTITION BY variable; -- Minute averages (InfluxDB 3) SELECT date_bin(INTERVAL '1 minute', time) AS minute, avg(wert) FROM messwerte WHERE variable = 'Temperatur' AND time > now() - INTERVAL '1 hour' GROUP BY 1 ORDER BY 1; For VictoriaMetrics and Prometheus (PromQL, e.g. in Grafana): .. code-block:: text messwerte_wert{variable="Temperatur"} # trend avg_over_time(messwerte_wert{variable="Temperatur"}[1m]) # minute average last_over_time(messwerte_wert{projekt="Anlage 1"}[1h]) # latest value per variable **Events in the database:** With *Also write events and notes* the trigger events and the notes are stored in the database in addition to the event log (file) – e.g. for your own evaluations or as annotations in Grafana. * **SQLite, MariaDB, PostgreSQL/TimescaleDB, QuestDB, InfluxDB 3:** table *table* + ``_ereignisse`` (i.e. ``messwerte_ereignisse``), one record per event with ``zeit`` (came, UTC), ``projekt``, ``id``, ``trigger_name``, ``prioritaet`` (priority), ``meldung`` (message), ``gegangen`` (went), ``quittiert`` (acknowledged), ``benutzer`` (acknowledged by or author of the note), ``notiz`` (note) and ``quittierpflicht`` (acknowledgement required) (InfluxDB: time column ``time``, went/acknowledged as text, plus ``dauer_s``). When an event goes or is acknowledged, the record is updated. On start the logger synchronises all events of the log – including older ones and those acknowledged in the event viewer in the meantime. * **VictoriaMetrics, Prometheus:** metrics *table* + ``_ereignisse_aktiv`` (1 when coming, 0 when going; notes 1) and ``_ereignisse_quittiert`` (1, label ``benutzer``) with the labels ``projekt``, ``id``, ``trigger_name``, ``prioritaet`` and ``meldung``. Only new transitions are written; on start those of the last 10 minutes. * A project name should be unique per logger: a record is identified by project, ID and time. .. code-block:: sql -- Open (not acknowledged) alarms SELECT zeit, trigger_name, meldung FROM messwerte_ereignisse WHERE quittierpflicht = 1 AND quittiert IS NULL AND prioritaet = 'Alarm' ORDER BY zeit; -- Most frequent events of the last 30 days (PostgreSQL) SELECT trigger_name, count(*) FROM messwerte_ereignisse WHERE notiz = 0 AND zeit > now() - interval '30 days' GROUP BY 1 ORDER BY 2 DESC; **Operation:** * Writing is done in a separate thread about once per second in batches; display and reading from the controller are not slowed down by this. * In the status bar (and in the web server) a separate **LED “Database”** shows the state; the tooltip gives the number of values written. * If the database cannot be reached, the values stay in memory (up to about 2 million values) and are written after reconnecting. Values not yet written when exiting are reported in the status line. * **Drivers:** SQLite is included in Python. MariaDB needs ``PyMySQL``, TimescaleDB/PostgreSQL ``psycopg`` (``pip install PyMySQL "psycopg[binary]"``); both are included in the installer. QuestDB, InfluxDB 3, VictoriaMetrics and Prometheus need no library. * For Grafana: create a data source *MySQL* or *PostgreSQL* (QuestDB: plugin *QuestDB* or *PostgreSQL* on port 8812; InfluxDB 3: *InfluxDB* with query language *SQL*; VictoriaMetrics and Prometheus: *Prometheus*); the time column is ``zeit`` (InfluxDB: ``time``, UTC). * **Grafana dashboard like in the logger:** **File › Export Grafana dashboard …** in the configuration program saves a dashboard as a JSON file; upload it in Grafana via *Dashboards › New › Import* and choose the data source of the database. Taken over are the pages (as rows; layout *Tabs*: only the first one expanded), the arrangement of the charts (one below the other, side by side, grid), per chart the variables with colours, Y axes (left/right, fixed limits, axis name) and BOOL as a step line, the time range (*Window [s]*) and a selection **Project** at the top of the dashboard – so one dashboard serves several plants with the same configuration. Possible with VictoriaMetrics, Prometheus, TimescaleDB/PostgreSQL, MariaDB, QuestDB and InfluxDB 3 (not SQLite). After changes to charts, export again and overwrite on import. With *Also write events and notes* the dashboard contains the annotation **Ereignisse** (events): triggers and notes as a vertical line or region (comes to goes) in all charts, priority as tag (can be switched off at the top of the dashboard). * **Up-to-dateness in Grafana:** the dashboard queries again every **5 s** (smallest default of Grafana). VictoriaMetrics does not show the **last 30 s** in queries yet. The logger's web server is meant for the live display; if you still want Grafana faster, change it *optionally*: in Grafana ``min_refresh_interval = 1s`` (``grafana.ini`` or ``GF_DASHBOARDS_MIN_REFRESH_INTERVAL``) and the refresh of the dashboard at the top right, for VictoriaMetrics the start parameter ``-search.latencyOffset=2s``. Both lines are ready (commented out) in ``docker/docker-compose.yml``. * **Test environment:** in the folder ``docker``, ``docker compose up -d`` starts TimescaleDB, QuestDB, InfluxDB 3 Core, VictoriaMetrics, Prometheus and Grafana with ready-made data sources (access data in ``docker/.env``). SQLite files can be read with Grafana's SQLite plugin. .. figure:: images/en/grafana_dashboard.png :alt: Grafana dashboard from the export :width: 100% :align: center Exported Grafana dashboard (VictoriaMetrics): layout, axes and colours as in the logger, at the top the selection *Project*. .. _db-lesen: Read mode: displaying recordings from the database ---------------------------------------------------------------------- In the logger, **File › Load from database …** (``Ctrl+D``) loads a freely chosen time range from the database and displays it in **offline mode** – with rulers, value table, screenshots and PID tuning as with a loaded CSV file. It reads from the database of the loaded configuration; the database is only read, a running recording (also of another logger) can continue writing meanwhile. .. figure:: images/en/datenbank.png :alt: Dialog Load from database :width: 85% :align: center Dialog “Load from database”: choose variables, time range and resolution. .. list-table:: :header-rows: 1 :widths: 25 75 * - Area - Meaning * - Database - Shows the source. **Choose SQLite file …** reads any SQLite file instead (e.g. a copy from another computer); **Database of the configuration** returns. * - Project - Project name under which the values were stored (default: project of the configuration). *(all projects)* combines variables of the same name of all projects. * - Variables - All variables in the database with first and last time and number of values. Initially the variables of the current configuration are ticked. **All**, **None**, **As in configuration** and the filter field help with many variables. * - Time range - **From** / **To** (local time) with calendar, or by button: *Last hour*, *Last 24 h*, *Last 7 days*, *Last 30 days* (each up to the last stored value of the chosen variables), *Today*, *Yesterday*, *All*. * - Resolution - *Automatic*: raw data as long as there are at most 20,000 points per variable, otherwise averages on a suitable grid (1 s, 2 s, 5 s … 1 day). *Raw data*: every stored value. *Average per 1 s … per day*: fixed grids. The averages are computed by the database itself – so even months of data can be surveyed quickly. * - Fill missing values with the last value - For recordings with **Write changes only** (preset there): a missing value means “unchanged”, the curve runs continuously. Without tick gaps appear. * - Count values - Determines the exact number of values in the time range (above it there is an estimate from the variable list). **Load and display** reads the values in the background; the progress is shown at the bottom of the window, **Cancel** stops reading. Then the logger switches to offline mode. Colours, charts and axes come from the configuration; variables missing there appear in the first chart. The status line gives source, time range and resolution. A running recording is stopped when loading (as when loading a CSV file); **▶ Start** begins a new one. Notes: * Timestamps are stored in UTC in the database; they are displayed in local time. * With averages the timestamp is in the middle of the grid interval (e.g. 10:00:30 for 10:00:00 to 10:00:59). Minimum and maximum within an interval are not visible – choose raw data or a finer grid for short peaks. * To protect memory, the logger reads at most 20 million values at once; above that a note asks you to choose a shorter time range or averages. * With MariaDB and PostgreSQL the user only needs the SELECT right. .. _ereignisse: Triggers and event log ====================================================================== A **trigger** monitors a condition on the variables, e.g. ``{Temperatur} > 80``. As soon as it is met, the logger writes an entry with timestamp to the **event log** (a text file). The number of events not yet acknowledged is shown in the logger's status bar; acknowledgement is done in the **event viewer** or in the browser (`Analysing in the browser`_). Creating triggers ---------------------------------------------------------------------- Configuration program, tab **Triggers & events** → **Edit triggers …**. .. figure:: images/en/trigger_editor.png :alt: Trigger editor :width: 90% :align: center The trigger editor: one row per trigger, faulty rows are marked red. .. list-table:: :header-rows: 1 :widths: 22 78 * - Column - Meaning * - Active - Only active triggers are evaluated. Disabled triggers may also be faulty (e.g. after renaming a variable). * - Name - Name of the trigger (unique, without ``;``); written to the event log. * - Condition - Expression as for `calculated variables `__. Result not equal to 0 = met. Examples: ``{Temperatur} > 80``, ``{Druck} < 2 and {Pumpe} == 1``, ``abs(ddt({Füllstand})) > 5``, ``{Störung} == 1``. Variables without value (no connection) count as *not met*. **Edit condition …** (or double-click) opens the formula editor with variable list and test values. * - Message text - Text of the entry. ``{Name}`` is replaced by the value of the variable at the time of the event, e.g. ``Temperature too high: {Temperatur} °C``. Empty = the condition itself. * - Priority - *Info*, *Warning* or *Alarm* (colour in the viewer, filter). * - Delay - The condition must be met **continuously** for this many seconds before the event is raised (suppresses short peaks). 0 = immediately. * - Clear - Also log the end of the event (condition false again). * - Acknowledge - The event must be acknowledged and is counted in the status bar until then. Without tick it is only logged. A trigger fires **once per edge**: only when the condition becomes false and then true again is a new event created. The triggers are checked with every measurement cycle – also in headless operation – and apply from the next start of the recording. In demo mode without own triggers there are two example triggers (*Übertemperatur*, *Druck niedrig*). Event file ---------------------------------------------------------------------- Field **Event file** in the same tab; empty = ``/_ereignisse.csv``. The file is only appended to (never changed or archived) and can be opened with Excel (semicolon, UTF-8): .. code-block:: text ID;Zeit;Art;Trigger;Priorität;Text;Benutzer 17;2026-10-15 16:20:01.250;KOMMT;Übertemperatur;Alarm;Temperatur zu hoch: 81.37 °C; 17;2026-10-15 16:22:40.100;GEHT;Übertemperatur;Alarm;; 17;2026-10-15 16:25:12.000;QUITTIERT;Übertemperatur;Alarm;;mmuster *Art* (kind) is ``KOMMT`` (raised), ``GEHT`` (cleared) or ``QUITTIERT`` (acknowledged); rows with the same *ID* belong to the same event. For ``QUITTIERT`` the column *Benutzer* (user) contains the Windows user name. ``-`` in the column *Benutzer* of a ``KOMMT`` row means “no acknowledgement required”. The file format is the same in all languages. Display in the status bar ---------------------------------------------------------------------- .. figure:: images/en/ereignis_statusleiste.png :alt: Event counter in the status bar :align: center Red background: three events are not yet acknowledged. On the right of the status bar the button **🔔** shows the number of open (not acknowledged) events; with open events it is red. A click on it – or **File → Event log …** (Ctrl+E) – opens the viewer. Each new event also appears as a message in the status bar (``⚠ Alarm: …``). The counter also works without a running recording, e.g. if a headless logger on the same computer writes to the file. In the web server “🔔 n open” is shown at the top (tooltip: the open events); acknowledgement is only possible in the viewer. Event viewer and acknowledgement ---------------------------------------------------------------------- .. figure:: images/en/ereignis_viewer.png :alt: Event viewer :width: 90% :align: center The event viewer: open events coloured by priority, completed ones grey. * The table shows the newest events at the top: number, raised, cleared, priority, trigger, message and acknowledgement (time and user or **open**). * Filters: **open only**, priority, search field (trigger or message). * **Acknowledge selected** (or double-click a row) acknowledges the selected events, **Acknowledge all** all open ones. * The display updates itself as soon as new events arrive (F5 = immediately). * **Show in chart** (button or right-click on a row, only in the logger): the logger switches to offline mode and shows the time range around the event, **ruler 1** on the start (coming), **ruler 2** on the end (going). If the values are no longer in memory, it loads them from the database of the configuration (if one is set; 10 minutes before and after the event), otherwise the matching CSV file from the CSV folder or the archive. * **Open folder** shows the event file in the file manager. .. figure:: images/en/ereignis_diagramm.png :alt: Event in the chart :width: 95% :align: center After “Show in chart”: time range around the event, ruler 1 on coming, ruler 2 on going. The viewer can also be started **on its own** – e.g. next to a headless logger or on another computer with access to the file (network drive): .. code-block:: text PLCLogger.exe --ereignisse (event log of the last used configuration) PLCLogger.exe --ereignisse plant.json (event log of this configuration) PLCLogger.exe --ereignisse D:\logs\log_ereignisse.csv The installed version has the shortcut *PLC Ereignisprotokoll* in the start menu for this. In the configuration program **Show event log …** opens the same viewer. .. _benachrichtigungen: Notifications ---------------------------------------------------------------------- When an event comes, the logger can pass it on immediately – by **e-mail**, into a **Microsoft Teams** or **Slack** channel, to any **webhook** (JSON), as a **push message to the phone** with the app *ntfy* or via **Telegram**. Set it up in the configuration program, tab *Triggers & events*, **Notifications …**; next to it you see whether and where notifications go. .. figure:: images/en/benachrichtigungen.png :alt: Notifications dialog :width: 60% :align: center Notifications: at the top when to notify, below one tab per channel. **When to notify:** * **Notify on events** – main switch. * **Priority** – from *Info*, *Warning* (default) or only *Alarm*. * **Only triggers** – empty = all; otherwise the names separated by commas. * **Also notify when an event goes** – an additional message when the condition is no longer met (only if the coming was notified). * **Lock time per trigger** (default 300 s) – if the same trigger comes again within this time, no further message is sent; the next message states how many were suppressed. Prevents message floods from a fluttering signal. The message contains priority, trigger, message text, time, project and computer name. **Channels** (one tab each, can be enabled individually): * **E-mail:** SMTP server, port (587 with STARTTLS, 465 with SSL/TLS, 25 unencrypted), user and password (empty = without login), sender and recipients (several separated by commas). * **Teams / Slack / Webhook:** *Microsoft Teams (Workflows)* – in the Teams channel under *Workflows* create the template "Post to a channel when a webhook request is received" and enter its address; the message appears as a card, alarms in red. *Slack* – address of an *incoming webhook*. *Generic (JSON)* – sends title, text, trigger, priority, type (KOMMT/GEHT), time, project and computer as JSON by POST, e.g. to Node-RED, Home Assistant or your own system. * **ntfy (push):** install the app *ntfy* on the phone and subscribe to a topic; enter the address with topic here, e.g. ``https://ntfy.sh/plant-4711-xyz``. Alarms arrive with the highest urgency. On ``ntfy.sh`` anybody who knows the name of the topic can read along – choose a name that is hard to guess or run your own ntfy server (then enter an access token if needed). * **Telegram:** create a bot with *@BotFather* (gives the bot token), send the bot a message and enter the chat ID (e.g. via *@userinfobot*). **Send test message** sends a test via all enabled channels and shows ✓ or the error for each channel. Sending happens in the background, recording does not wait for it; errors (server not reachable, wrong login) are shown in the status bar or the log file. Notifications also work in headless operation – the computer needs access to the mail server or the internet for this. .. note:: Passwords and tokens are stored in plain text in the configuration file. Make the file accessible to authorised persons only and use a separate account for e-mail. .. _notizen: Notes (own entries) ---------------------------------------------------------------------- Besides the triggers, **notes can be written by hand** to the event log, e.g. “Valve V12 replaced” or “Setpoint changed to 65 °C” – so the same file later tells why a trend changed. * In the logger: **File → Note to the event log …** (Ctrl+M). In offline mode the time of **ruler 1** is preset – so a point in the trend can be commented afterwards. * In the event viewer: **Add note …**. .. figure:: images/en/notiz.png :alt: Entering a note :align: center Time, text and author of a note. Time (default: now), text (also multi-line) and author (default: Windows or Linux user name) can be chosen freely. Notes are stored as kind ``NOTIZ`` in the file, appear in the viewer with a green background and 📝 and need no acknowledgement. The filter **notes only** shows only them. .. code-block:: text 18;2026-10-16 09:12:00.000;NOTIZ;Notiz;Notiz;Valve V12 replaced;mmuster .. _trigger-aufzeichnung: Recording by trigger (pre- and post-trigger) ====================================================================== .. figure:: images/en/config_aufzeichnung_trigger.png :alt: Tab Recording :width: 90% :align: center Tab Recording: recording by trigger with start condition, pre- and post-trigger time. Instead of recording continuously, the logger can write to the CSV file and database only when something happens – with the values **before** the event (pre-trigger) and **after** it (post-trigger). Typical applications: fault analysis, test cycles, batches. **Settings** (configuration program, tab *Recording*): * **Recording:** *By trigger with pre- and post-trigger time*. * **Start condition:** a condition as for triggers, e.g. ``{Druck} > 5``, ``{Störung} == 1`` or ``abs(ddt({Kraft})) > 100``; **…** opens the formula editor with variable list and check. All variables including the calculated ones can be used. * **Pre-trigger:** this many seconds before the trigger are saved as well. For this the logger keeps the latest measurements in a **ring buffer**. * **Post-trigger:** saving continues this long after the condition has ended. If the condition becomes true again during this time, the capture is extended. * **max.:** maximum duration of a capture (*unlimited* = 0). After that the capture ends even if the condition is still met; the next one only starts after the condition has been false once. **Sequence:** After the start the status bar shows *⏸ waiting for trigger*. When the condition becomes true, a capture begins (*⏺ Capturing*): a **new CSV file** (``__