{"id":31034487,"url":"https://github.com/zonfacter/twincat3_tpy_csv","last_synced_at":"2026-01-19T13:00:51.095Z","repository":{"id":313467998,"uuid":"1051536778","full_name":"zonfacter/TwinCAT3_TPY_CSV","owner":"zonfacter","description":"Konvertiert Beckhoff TwinCAT *.tpy in SPS-Analyzer-kompatible CSV – inkl. ARRAY/UDT-Entfaltung, rekursiv (optional), Chunking \u0026 Whitelist/Blacklist.","archived":false,"fork":false,"pushed_at":"2025-09-06T09:03:11.000Z","size":524,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-14T02:28:14.130Z","etag":null,"topics":["analyzer","converter","csv","tpy","twincat","twincat2","twincat3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zonfacter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-06T07:41:13.000Z","updated_at":"2025-09-06T09:03:15.000Z","dependencies_parsed_at":"2025-09-06T09:25:02.134Z","dependency_job_id":"77915358-413a-4821-a63f-c38606ba8a0c","html_url":"https://github.com/zonfacter/TwinCAT3_TPY_CSV","commit_stats":null,"previous_names":["zonfacter/twincat3_tpy_csv"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/zonfacter/TwinCAT3_TPY_CSV","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonfacter%2FTwinCAT3_TPY_CSV","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonfacter%2FTwinCAT3_TPY_CSV/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonfacter%2FTwinCAT3_TPY_CSV/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonfacter%2FTwinCAT3_TPY_CSV/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zonfacter","download_url":"https://codeload.github.com/zonfacter/TwinCAT3_TPY_CSV/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonfacter%2FTwinCAT3_TPY_CSV/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28568833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T12:50:50.164Z","status":"ssl_error","status_checked_at":"2026-01-19T12:50:42.704Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analyzer","converter","csv","tpy","twincat","twincat2","twincat3"],"created_at":"2025-09-14T02:20:55.733Z","updated_at":"2026-01-19T13:00:51.076Z","avatar_url":"https://github.com/zonfacter.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# convert\\_tpy\\_csv – README\n\nKonvertiert eine **Beckhoff TwinCAT .tpy** in eine CSV im Format des **SPS‑Analyzer 6** (TwinCAT‑Modul), inkl. Entfaltung von **ARRAYs** und **STRUCT/UDT‑SubItems**.\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/social-preview.png\" alt=\"TwinCAT .tpy → CSV – SPS-Analyzer 6 kompatibel\" width=\"60%\"\u003e\n\u003c/p\u003e\n\n\n---\n\n## TL;DR\n\n```bash\npython convert_tpy_csv.py [--gui] [--no-recurse] \u003cEingabe.tpy\u003e \u003cAusgabe.csv\u003e\n```\n\n* **Header** wie vom SPS‑Analyzer erwartet:\n\n  1. `Beckhoff TwinCat V2-PLC-Symbolfile`\n  2. Anzahl der Datensätze\n  3. Ab Zeile 3: Datensätze (Semikolon‑separiert)\n* **Großdateien** werden automatisch in Teile gesplittet (max. **1 670 000 Gesamtzeilen** je Datei, inkl. Header).\n* **Rekursive Entfaltung** von verschachtelten UDTs/FBs ist **standardmäßig aktiv** (siehe unten). Mit `--no-recurse` kann sie deaktiviert werden.\n* **GUI-Start** mit `--gui` (öffnet eine Tkinter-Oberfläche zur Dateiauswahl; wird ebenfalls geöffnet, wenn keine Pfade angegeben sind und die Default-Datei nicht existiert).\n* **Header** wie vom SPS‑Analyzer erwartet:\n\n  1. `Beckhoff TwinCat V2-PLC-Symbolfile`\n  2. Anzahl der Datensätze\n  3. Ab Zeile 3: Datensätze (Semikolon‑separiert)\n* **Großdateien** werden automatisch in Teile gesplittet (max. **1 670 000 Gesamtzeilen** je Datei, inkl. Header).\n\n---\n\n## Voraussetzungen\n\n* **Python ≥ 3.10** (wegen `int | None` Type‑Hints). Getestet mit **3.13**.\n* Keine externen Abhängigkeiten. Nur Python‑Standardbibliothek (`xml.etree.ElementTree`, `csv`, `re`, `pathlib`, `sys`).\n* **Optional für GUI**: Tkinter (unter Linux z. B. Paket `python3-tk`).\n\n---\n\n## Aufruf / Parameter\n\n```bash\npython convert_tpy_csv.py [--gui] [--no-recurse] [--no-array-recurse] [--only \u003cWhitelist.txt\u003e] [--skip \u003cBlacklist.txt\u003e] \u003cEingabe.tpy\u003e \u003cAusgabe.csv\u003e\n```\n\n**Optionale Flags:**\n\n* `--no-recurse` → deaktiviert **alle** rekursiven Entfaltungen (Top‑UDTs/FBs \u0026 Arrays).\n* `--no-array-recurse` → deaktiviert nur die **rekursive Entfaltung von UDT‑Array‑Elementen**.\n* `--gui` → öffnet eine **Tkinter-Oberfläche** zur Auswahl von TPY/CSV/Listen.\n* `--only \u003cDatei\u003e` → **Whitelist** (Regex je Zeile). Nur UDT‑Namen, die einem Muster entsprechen, werden rekursiv entfaltet.\n* `--skip \u003cDatei\u003e` → **Blacklist** (Regex je Zeile). UDT‑Namen, die einem Muster entsprechen, werden **nicht** rekursiv entfaltet.\n\n**Beispiele (Windows CMD):**\n\n````bat\nREM absolut\npython convert_tpy_csv.py C:\\Projekte\\TwinCAT\\Plc.tpy C:\\Export\\output.csv\n\nREM relativ (aus C:\\Projekte)\npython convert_tpy_csv.py TwinCAT\\Plc.tpy Export\\output.csv\n\nREM ohne Rekursion (alles)\npython convert_tpy_csv.py --no-recurse TwinCAT\\Plc.tpy Export\\output.csv\n\nREM nur Array‑Rekursion aus\npython convert_tpy_csv.py --no-array-recurse TwinCAT\\Plc.tpy Export\\output.csv\n\nREM Whitelist verwenden\npython convert_tpy_csv.py --only cfg\\udt_whitelist.txt TwinCAT\\Plc.tpy Export\\output.csv\n\nREM Blacklist verwenden\npython convert_tpy_csv.py --skip cfg\\udt_blacklist.txt TwinCAT\\Plc.tpy Export\\output.csv\n\nREM Whitelist + Blacklist (Whitelist zuerst, dann Blacklist)\npython convert_tpy_csv.py --only cfg\\udt_whitelist.txt --skip cfg\\udt_blacklist.txt TwinCAT\\Plc.tpy Export\\output.csv\n```bash\npython convert_tpy_csv.py [--no-recurse] [--no-array-recurse] \u003cEingabe.tpy\u003e \u003cAusgabe.csv\u003e\n````\n\n**Optionale Flags:**\n\n* `--no-recurse` → deaktiviert **alle** rekursiven Entfaltungen (Top‑UDTs/FBs \u0026 Arrays).\n* `--no-array-recurse` → deaktiviert nur die **rekursive Entfaltung von UDT‑Array‑Elementen**.\n\n**Beispiele (Windows CMD):**\n\n```bat\nREM absolut\npython convert_tpy_csv.py C:\\Projekte\\TwinCAT\\Plc.tpy C:\\Export\\output.csv\n\nREM relativ (aus C:\\Projekte)\npython convert_tpy_csv.py TwinCAT\\Plc.tpy Export\\output.csv\n\nREM ohne Rekursion (alles)\npython convert_tpy_csv.py --no-recurse TwinCAT\\Plc.tpy Export\\output.csv\n\nREM nur Array‑Rekursion aus\npython convert_tpy_csv.py --no-array-recurse TwinCAT\\Plc.tpy Export\\output.csv\n```\n\n\u003e Achtung: `\\tpy\\Plc.tpy` (führender Backslash) wird als UNC‑Pfad interpretiert und führt zu *FileNotFoundError*. Entweder **relativ ohne führenden Backslash** oder **absolut** angeben.\n\n**Standardwerte (nur als Fallback in dev/test):**\n\n* Eingabe: `/mnt/data/Plc.tpy`\n* Ausgabe: `/mnt/data/output.csv`\n\n---\n\n## Ausgabeformat (CSV)\n\n**Spaltenreihenfolge:**\n\n```\nIGroup; IOffset; Name; Comment; Type; BitSize; BitOffs; DefaultValue; ActualAddress\n```\n\n**Header:**\n\n```\nBeckhoff TwinCat V2-PLC-Symbolfile\n\u003cAnzahl_Datensätze\u003e\n\u003cDatensätze …\u003e\n```\n\n### Semantik der Spalten\n\n* **IGroup**: wie in der .tpy\n* **IOffset**:\n\n  * **ARRAY‑Elemente:** = **ActualAddress** des Elements\n  * **STRUCT/UDT‑SubItems:** = **ActualAddress** des SubItems\n  * **Top‑Symbolzeilen:** = Basisadresse des Symbols\n* **Name**:\n\n  * **Top‑Symbol:** Original‑Name aus .tpy\n  * **ARRAY‑Element:** `Name[index]`\n  * **STRUCT/UDT‑SubItem:** **qualifizierter Name** `Parent.SubItem` (z. B. `prgMain.tonTempDaten2.IN`)\n* **Comment**: gekürzt auf 200 Zeichen, ohne Zeilenumbrüche\n* **Type**: Datentyp (inkl. `ARRAY [...] OF …`)\n* **BitSize**: Bitgröße des Elements (s. Auflösung unten)\n* **BitOffs**: Bit‑Offset **relativ zur Basis** (ARRAY‑Basis bzw. STRUCT‑Parent)\n* **DefaultValue**: falls im `\u003cDefault\u003e\u003cValue\u003e` vorhanden\n* **ActualAddress**: `Basisadresse + (BitOffs // 8)`\n\n---\n\n## Entfaltungs‑/Adressierungsregeln\n\n### Rekursive Entfaltung (Standard: EIN)\n\n* **Top‑UDTs/FBs:** SubItems, deren **Type** wiederum ein `\u003cDataType\u003e` ist (z. B. `Tc2_Standard.R_TRIG`, `Tc2_Standard.TON`, `Tc2_MC2.*`, `TC3_UniLib.*`), werden **weiter entfaltet**.\n* **Arrays von UDTs:** `ARRAY [...] OF \u003cUDT\u003e` → jedes Element wird zusätzlich **rekursiv entfaltet** (z. B. `.arrAxis[1].PlcToNc.*`).\n* **Name:** bei jedem Schritt vollständig qualifiziert (`Parent.SubItem[.SubSubItem…]` bzw. `ArrayName[i].SubItem…`).\n* **Offset/Adresse:** absolute `BitOffs` wird kumuliert (Summe der relativen Offsets); `ActualAddress = Basis + (BitOffs // 8)`; `IOffset = ActualAddress`.\n* **Deaktivieren:**\n\n  * alle Rekursionen: `--no-recurse`\n  * nur Array‑Rekursion: `--no-array-recurse`\n* **Whitelist/Blacklist:**\n\n  * `--only \u003cDatei\u003e`: es werden **nur** UDT‑Namen rekursiv entfaltet, die auf **mindestens ein** Regex in der Datei matchen.\n  * `--skip \u003cDatei\u003e`: UDT‑Namen, die auf **irgendein** Regex matchen, werden **nicht** rekursiv entfaltet (greift **nach** der Whitelist‑Prüfung).\n  * **Dateiformat:** eine Regex je Zeile; leere Zeilen und Zeilen beginnend mit `#`, `;` oder `//` sind Kommentare.\n  * **Case‑Sensitivity:** Regex ist standardmäßig **case‑sensitiv**; für Case‑Insensitive `(?i)` als Präfix im Regex verwenden.\n\n### Top‑Symbol\n\n```\nIGroup; IOffset=basis; Name; …; BitOffs=\"\"; ActualAddress=basis\n```\n\n### ARRAY\n\n* **Basisadresse** = `IOffset` aus Top‑Symbol\n* **Element‑Name** = `Name[index]`\n* **BitOffs (Element)** = `(index - start) * per_element_bits`\n* **ActualAddress (Element)** = `Basis + (BitOffs // 8)`\n* **IOffset (Element)** = **ActualAddress (Element)**\n\n### STRUCT / UDT (SubItems)\n\n* **Basisadresse** = `IOffset` aus Top‑Symbol\n* **SubItem‑Name** = `Parent.SubItem`\n* **ActualAddress (SubItem)** = `Basis + (BitOffs // 8)`\n* **IOffset (SubItem)** = **ActualAddress (SubItem)**\n\n---\n\n## Größenauflösung (BitSize je Element)\n\nReihenfolge der Ermittlung (erste zutreffende Regel gewinnt):\n\n1. **Primitive** (`PRIM_BITS`): `BOOL, BYTE, SINT, USINT, WORD, INT, UINT, DWORD, DINT, UDINT, REAL, LWORD, LINT, ULINT, LREAL`\n2. **STRING/WSTRING**: `STRING(n)` → `(n+1) * 8` Bit; `WSTRING(n)` → `(n+1) * 16` Bit\n3. **Zeit/Datum** (`SPECIAL_BITS`): z. B. `TIME: 32`, `DATE_AND_TIME: 32`, `LTIME: 64`, …\n4. **UDT/Funktionsbausteine aus `\u003cDataTypes\u003e`**: nutzt `\u003cBitSize\u003e` des passenden `\u003cDataType\u003e`\n5. **Fallback**: `symbol_bitsize / element_count`, mindestens **8 Bit**\n\nDamit werden u. a. korrekt behandelt:\n\n* **Tc2\\_Standard**: `TON`, `R_TRIG` (über `\u003cDataTypes\u003e`)\n* **Tc2\\_MC2.\\*:** `ST_McOutputs`, `AXIS_REF`, `MC_ReadParameter`, `MC_MoveAbsolute/Velocity/Modulo`, …\n* **TC3\\_UniLib.\\*:** `ST_UniBaustein`, `ST_NcAchsen`, `FB_UniWkzgAnstg`, …\n\n---\n\n## Multi‑File‑Output (Chunking)\n\n* Max. **1 670 000 Gesamtzeilen pro Datei** (inkl. 2 Headerzeilen) → **1 669 998 Datensätze** je Datei.\n* Erste Datei heißt wie angegeben (z. B. `output.csv`).\n* Folge‑Dateien: `output_2.csv`, `output_3.csv`, … (Zeile 2 enthält dort jeweils die **Teil‑Anzahl** der Datensätze).\n\n**Konstanten im Script:**\n\n```python\nMAX_TOTAL_LINES_PER_FILE = 1_670_000\nHEADER_LINES = 2\n```\n\n## Datenmenge \u0026 Performance\n\n* Die Datensatzanzahl kann durch die **rekursive Entfaltung** von UDTs/FBs **sehr stark ansteigen**.\n* Praxisbeispiel: ohne Rekursion ≈ **41 575** Datensätze → mit Rekursion **666 130** Datensätze (gleiche .tpy).\n* Plane entsprechend **Laufzeit, RAM und Dateigröße** ein. Der SPS‑Analyzer lädt große CSVs spürbar langsamer.\n* Wenn die Datei zu groß wird: Script mit `--no-recurse` starten, oder zusätzliche Filterlogik einbauen (kann bei Bedarf ergänzt werden).\n* Das **Chunking** splittet automatisch; jede Teil‑Datei hat eine eigene Zeile‑2‑Zählung (Datensätze dieses Teils).\n\n---\n\n## Beispiele\n\n### ARRAY (BOOL)\n\n```\n61472;51520300;.arrTwinSafeGroupOtherError;;ARRAY [1..5] OF BOOL;40;;;51520300\n61472;51520300;.arrTwinSafeGroupOtherError[1];;BOOL;8;0;;51520300\n61472;51520301;.arrTwinSafeGroupOtherError[2];;BOOL;8;8;;51520301\n61472;51520302;.arrTwinSafeGroupOtherError[3];;BOOL;8;16;;51520302\n61472;51520303;.arrTwinSafeGroupOtherError[4];;BOOL;8;24;;51520303\n61472;51520304;.arrTwinSafeGroupOtherError[5];;BOOL;8;32;;51520304\n```\n\n### STRUCT/UDT – qualifizierte SubItems (`Tc2_Standard.TON`)\n\n```\n16448;777600;prgMain.tonTempDaten2;;Tc2_Standard.TON;256;;;777600\n16448;777608;prgMain.tonTempDaten2.IN;;BOOL;8;64;;777608\n16448;777612;prgMain.tonTempDaten2.PT;;TIME;32;96;;777612\n16448;777616;prgMain.tonTempDaten2.Q;;BOOL;8;128;;777616\n16448;777620;prgMain.tonTempDaten2.ET;;TIME;32;160;;777620\n16448;777624;prgMain.tonTempDaten2.M;;BOOL;8;192;;777624\n16448;777628;prgMain.tonTempDaten2.StartTime;;TIME;32;224;;777628\n```\n\n---\n\n## Fehlerbehebung\n\n* **FileNotFoundError**: In Windows kein führender Backslash (UNC). Pfad absolut oder relativ angeben, z. B. `tpy\\Plc.tpy` statt `\\tpy\\Plc.tpy`.\n* **Falsche IOffset‑Werte**: Prüfe, ob der Fall **ARRAY** (Element → `IOffset=ActualAddress`) oder **STRUCT** (SubItem → `IOffset=ActualAddress`) ist. Top‑Symbolzeilen behalten die Basisadresse.\n* **Sondertypen fehlen**: Ergänze bei Bedarf `PRIM_BITS`/`SPECIAL_BITS`. UDTs werden i. d. R. über `\u003cDataTypes\u003e` automatisch erkannt.\n* **Excel‑Kompatibilität**: Standard‑Encoding ist `UTF‑8`. Falls nötig, Ausgabe auf `cp1252` ändern.\n\n---\n\n## Anpassungspunkte im Code\n\n* **Typgrößen**: `PRIM_BITS`, `SPECIAL_BITS`\n* **Chunk‑Größe**: `MAX_TOTAL_LINES_PER_FILE`, `HEADER_LINES`\n* **Kommentar‑Länge**: in `limit_comment()`\n\n---\n\n## Lizenz / Autor\n\nInterner Projekt‑Helper; keine externe Lizenzangabe erforderlich. Änderungen nach Bedarf.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzonfacter%2Ftwincat3_tpy_csv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzonfacter%2Ftwincat3_tpy_csv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzonfacter%2Ftwincat3_tpy_csv/lists"}