You are helping a maintenance engineer turn the drawings of ONE machine into a wiring table for LineKeeper On (LK On). LK On is a device that reads the machine's PLC. It compares this table with the PLC program by I/O address, so that a mechanic sees next to each signal the device, the wire, the terminal, the fuse and the sheet of the drawing. I attached the electrical drawing (PDF), maybe the pneumatic drawing, maybe a parts list. I may also have attached the PLC program export (.L5X). YOUR JOB: read every sheet and write ONE JSON file in the format "lkwiring/1" described below. === RULES THAT MATTER MOST === 1. Copy, never guess. Designators, wire numbers, terminals, ratings and catalog numbers go in exactly as printed. A missing row is better than a wrong row: a wrong fuse number sends a mechanic to the wrong place. - Could not read it: leave the field out. - Not sure: keep the row, add "status": "uncertain" and say why in "note". - Know it exists but could not read it at all: "status": "unread" with a "note" (then "at" may be left out). 2. Every row says where you read it: "at": [{"sheet": 9}]. The sheet number is the one printed in the title block. With two or more documents add "doc": the document's key. 3. Names prove nothing. Decide what a device is from its symbol and the words on the drawing, never from its tag. 4. Safety circuits (emergency stop, safety relay, door switch, light curtain, safety contactor): give each such device a "devices" row with "safety": true, and write one "safety" row that points at them. Do NOT put them into "feeds" or "mechanisms" and do not describe how the safety circuit works. This table never replaces the drawing for safety. 5. Do not make up the program side. See "program_key" below. === HOW TO WORK === Step 1. List the sheets: number, and title when one is printed. Say which hold PLC inputs and outputs, power, pneumatics. Step 2. PLC inputs and outputs first ("modules" and "points"). This is the part LK On can check against the program. One "points" row for EVERY channel the drawing shows, the spare ones too. Step 3. Show me the list of I/O blocks you found (label, inputs or outputs, number of channels, catalog number) with the "program_key" you propose for each and where you took it from. Wait for my answer if any key is unknown. Step 4. Devices and part numbers ("devices", "parts"). Step 5. Power ("rails", "feeds"): which breaker, fuse, power supply, relay or contactor each load gets its energy from. Step 6. Pneumatic and mechanical units ("mechanisms"). Step 7. What the drawing contradicts itself on ("conflicts") and what you could not trace ("open"). Step 8. Run the self-check at the end of this text, then give me the file. Giving the file: if you can create files, create ".lkwiring.json". Otherwise print the JSON in one code block. If a reply would be cut off, stop after a complete row, and continue from the next row when I write "continue". Plain JSON only: double quotes, no comments, no trailing commas. === THE FILE === { "format": "lkwiring/1", <- must be the FIRST key "machine": {"name": "...", "model": "...", "serial": "..."}, optional "program": {"name": "...", "controller": "catalog number"}, optional, only if I gave you the program "made": {"by": "ai", "checked": false, "tool": "", "at": ""}, "documents": [...], "modules": [...], "points": [...], "devices": [...], "rails": [...], "feeds": [...], "mechanisms": [...], "parts": [...], "safety": [...], "conflicts": [...], "open": [...] } "documents" needs at least one row. Any other table may be left out when you have nothing for it. Every row of every table has: "key" required. Unique inside its table. 1-64 characters from A-Z a-z 0-9 _ . : + / - (no spaces). Make it from the drawing, never from a counter: "IN2.3", "TS1", "feed.SSR1". "at" required: [{"sheet": N}] or [{"doc": "E", "sheet": N, "zone": "C4"}]. Several places are allowed. "status" optional: "read" (default), "uncertain", "unread". "note" optional, at most 500 characters. A "ref" below means a device designator exactly as printed ("BF13", "KM4", "1S3"). --- documents --- key ("E", "P"), title (as in the title block), kind: "electrical" | "pneumatic" | "combined" | "other", sheets (the highest sheet number). Optional: pages, missing_sheets [numbers], revision, date. --- modules: the PLC, its I/O cards, drives, the HMI --- label the drawing's name of the block: "IN2", "OUT7", "PLC", "DR1" role "controller" | "io" | "adapter" | "drive" | "hmi" | "other" dir for "io": "I" inputs, "O" outputs, "SI" / "SO" safety inputs / outputs program_key for "io": see below. Use null when it is not known. catalog catalog number printed on the drawing points number of channels first_channel 0 (default) or 1: how the drawing numbers the channels embedded true for inputs and outputs built into the controller itself Use the label as the key. Inputs and outputs built into the controller are two rows (one "I", one "O") with the same program_key; leave their catalog out when the drawing prints none. program_key is how LK On finds the card in the PLC program. It comes from the card's PLACE, never from its name: card in a slot of the controller's own rack, or the controller's built-in I/O ..... the slot number: "2" a device on the controller's network (remote I/O adapter, drive) ................. "@" + address: "@192.168.1.102" a card in a slot behind such an adapter ........................................... "@192.168.1.102/3" Where to take it from, in this order: a) The program export (.L5X), if I attached it. Look at the I/O addresses the program really uses: "Local:2:I.Data.3" -> the card is in slot 2 of the controller's rack -> "2". "Rack1:3:O.Data.0" -> find the module named Rack1, take the Address of its upstream port -> "@
/3". In the list each module has ParentModule and . A card the program never addresses: take its slot from the module list. b) The drawing, if it prints the PLC address beside the channels ("Local:2:I.Data.3", "I:2/3"). c) Otherwise ask me in Step 3. If I do not know either, write null. A block named IN2 is not proof of slot 2. With null LK On still loads the file, but lists those points as "not tied to the program" and compares nothing for them. --- points: one row per channel --- module a modules label channel the channel number as the drawing numbers it devices what is on the wire of this channel on the field side: ["BF13"] or [{"ref": "TS1", "terminal": "8"}]. May be empty only together with "spare": true. combine required when there are 2 or more devices: "series" | "parallel" | "unknown" (use "unknown" if not traced) spare true when the drawing marks the channel spare or leaves it free. A channel that is wired but has no device drawn is spare too: give its wire and path and say so in "note". wire wire number at the card path the way from the device to the card: [{"kind": "plug" | "cable" | "terminal" | "connector", "id": "W1", "pin": "4"}] function the drawing's words for the signal ("cups control at entry") signal "digital" (default) | "analog" safety true when the drawing marks the channel as part of a safety circuit Key: ".", for example "IN2.3". --- devices --- ref the designator as printed. No two devices, module labels or rail names may be equal, also not when compared without regard to upper and lower case. type one of: sensor, switch (push button, selector, limit switch), thermocouple, lamp, buzzer, coil, relay, contactor, ssr, breaker, fuse, disconnect, power_supply, transformer, rectifier, valve, hand_valve, cylinder, motor, drive, heater, temperature_controller, regulator, filter, fan, potentiometer, other type_words the drawing's word when type is "other" function, rating (as printed: "2 A", "315 W, 230 V") aka other designators the drawing uses for the same thing seen "drawn" (default) | "referenced" (named on a sheet but not drawn in this file) drawn_designator false when the drawing gives no designator and you had to name it yourself ("pump") safety true for a device of a safety circuit wired_to wiring to another device that is not power: [{"ref": "DR1", "terminal": "digital input"}] Write a row for every device you name anywhere else in the file. Use the ref as the key (replace spaces by _). A printed range ("1G18 - 4G18") is four devices: write four rows. --- rails: named potentials and air lines --- name ("+F11", "P1"), from (the ref of the device whose output it is, or null when the drawing does not show it), medium: "electric" (default) | "air", voltage ("24 V DC") --- feeds: who gets energy from whom --- load a ref, or a module label (the field power of that block) from a ref (breaker, fuse, power supply, relay, contactor), a rail name, or a module label (a drive feeding its motor) load_side "power" (default) | "control" (a coil or an enable input) | "contacts" (the supply that a relay's or contactor's contacts pass on) contact {"terminals": "11-14", "kind": "NO" | "NC"} when the load is fed THROUGH a contact of "from". Allowed only when "from" is a relay, contactor, switch or breaker. medium "electric" (default) | "air" wires [{"wire": "803"}] Typical chain: {"load": "KM4", "load_side": "contacts", "from": "QM4"} and {"load": "M4", "from": "KM4"}. A device that switches its load without a drawn contact (a temperature controller driving a solid-state relay): {"load": "SSR1", "load_side": "control", "from": "TS1"}, no "contact". "from" is never null. When the drawing does not show where a load is fed from, write no feed row and put it in "open". Key: "feed.", add ".control" or ".2" when one load has several rows. --- mechanisms: units on the pneumatic or mechanical sheets --- title the drawing's words ("FILLERS 1-4") drive [refs] what moves it: coils, contactors, a drive's module label. May be empty. valve ref. Leave it out for a unit without a valve (a motor on a drive). actuators [refs] cylinders, motors. Or [{"ref": "G1", "via": ["CR1"]}] for parts between valve and actuator. positions [{"sensor": "B18", "actuator": "1G18", "label": "down"}]. May be empty. Leave "actuator" out when the drawing shows the sensor beside a group and not on one cylinder. feedback "drawn" when positions is not empty; "none" when the drawing shows no position sensor; "unknown" when you did not read it. Required. air the rail name of the air line it is fed from extra [refs] other parts of the unit ALWAYS write "drive", "actuators" and "positions", as [] when there is nothing: a row without them is dropped. --- parts --- catalog (as printed), maker, words (the drawing's description), for: [refs or module labels] (at least one). At least one of catalog and words. Key: the catalog number with spaces replaced by _. --- safety --- {"key", "about": [refs or points keys], "text": "Emergency stop chain: see the sheet.", "at"} --- conflicts --- {"key", "kind": "designator" | "not_drawn" | "duplicate_page" | "missing_sheet" | "other", "text", "refs": [...], "at"} where the drawing contradicts itself. "refs" and "about" hold only designators that have a "devices" row; name any other in the text. --- open --- {"key", "text", "about": [refs or points keys], "at"} what you saw but could not trace === A SMALL EXAMPLE === {"format": "lkwiring/1", "machine": {"name": "Gate demo line"}, "made": {"by": "ai", "checked": false, "tool": "example", "at": "2026-11-05"}, "documents": [{"key": "E", "title": "Electrical schematic", "kind": "electrical", "sheets": 3}], "modules": [ {"key": "PLC", "label": "PLC", "role": "controller", "catalog": "1769-L33ER", "at": [{"sheet": 1}]}, {"key": "IN1", "label": "IN1", "role": "io", "program_key": "1", "dir": "I", "points": 16, "at": [{"sheet": 2}]}, {"key": "OUT2", "label": "OUT2", "role": "io", "program_key": "2", "dir": "O", "points": 8, "at": [{"sheet": 2}]}], "points": [ {"key": "IN1.0", "module": "IN1", "channel": 0, "devices": [], "spare": true, "at": [{"sheet": 2}]}, {"key": "IN1.3", "module": "IN1", "channel": 3, "devices": ["B1"], "wire": "103", "function": "bottle present", "at": [{"sheet": 2}]}, {"key": "IN1.7", "module": "IN1", "channel": 7, "devices": ["B2"], "wire": "107", "path": [{"kind": "terminal", "id": "X1", "pin": "7"}], "function": "gate out", "at": [{"sheet": 2}]}, {"key": "OUT2.0", "module": "OUT2", "channel": 0, "devices": ["Y1"], "wire": "200", "function": "gate valve", "at": [{"sheet": 2}]}, {"key": "OUT2.1", "module": "OUT2", "channel": 1, "devices": ["K1"], "wire": "201", "function": "conveyor on", "at": [{"sheet": 2}]}], "devices": [ {"key": "B1", "ref": "B1", "type": "sensor", "function": "bottle present", "at": [{"sheet": 2}]}, {"key": "B2", "ref": "B2", "type": "sensor", "function": "gate out", "at": [{"sheet": 2}]}, {"key": "Y1", "ref": "Y1", "type": "coil", "function": "gate valve", "at": [{"sheet": 2}]}, {"key": "K1", "ref": "K1", "type": "contactor", "at": [{"sheet": 1}, {"sheet": 2}]}, {"key": "Q1", "ref": "Q1", "type": "breaker", "rating": "6 A", "at": [{"sheet": 1}]}, {"key": "G1", "ref": "G1", "type": "power_supply", "rating": "24 V DC, 5 A", "at": [{"sheet": 1}]}, {"key": "F1", "ref": "F1", "type": "fuse", "rating": "2 A", "at": [{"sheet": 1}]}, {"key": "M1", "ref": "M1", "type": "motor", "function": "conveyor", "at": [{"sheet": 1}]}, {"key": "V1", "ref": "V1", "type": "valve", "rating": "5/2", "at": [{"sheet": 3}]}, {"key": "C1", "ref": "C1", "type": "cylinder", "function": "gate", "at": [{"sheet": 3}]}, {"key": "S0", "ref": "S0", "type": "switch", "function": "emergency stop", "safety": true, "at": [{"sheet": 1}]}], "rails": [ {"key": "+24F1", "name": "+24F1", "from": "F1", "voltage": "24 V DC", "at": [{"sheet": 1}]}, {"key": "P1", "name": "P1", "from": null, "medium": "air", "at": [{"sheet": 3}]}], "feeds": [ {"key": "feed.G1", "load": "G1", "from": "Q1", "at": [{"sheet": 1}]}, {"key": "feed.F1", "load": "F1", "from": "G1", "at": [{"sheet": 1}]}, {"key": "feed.IN1", "load": "IN1", "from": "+24F1", "at": [{"sheet": 2}]}, {"key": "feed.B1", "load": "B1", "from": "+24F1", "at": [{"sheet": 2}]}, {"key": "feed.K1.contacts", "load": "K1", "load_side": "contacts", "from": "Q1", "at": [{"sheet": 1}]}, {"key": "feed.M1", "load": "M1", "from": "K1", "at": [{"sheet": 1}]}], "mechanisms": [ {"key": "gate", "title": "GATE", "drive": ["Y1"], "valve": "V1", "actuators": ["C1"], "feedback": "drawn", "positions": [{"sensor": "B2", "actuator": "C1", "label": "out"}], "air": "P1", "at": [{"sheet": 3}]}], "parts": [ {"key": "E2E-X5ME1", "catalog": "E2E-X5ME1", "maker": "Omron", "words": "inductive sensor", "for": ["B1", "B2"], "at": [{"sheet": 2}]}], "safety": [ {"key": "estop", "about": ["S0"], "text": "Emergency stop chain: see the sheet.", "at": [{"sheet": 1}]}], "open": [ {"key": "P1-source", "text": "The drawing does not show where air line P1 comes from.", "about": [], "at": [{"sheet": 3}]}] } === SELF-CHECK BEFORE YOU GIVE ME THE FILE === LK On refuses the whole file when: "format" is not the first key or is not "lkwiring/1"; "documents" is empty; two rows of one table share a key; two refs, module labels or rail names are equal (ignoring case); two "io" module rows share a program_key and a dir; the text is not valid JSON. LK On drops a single row when: it names a ref that has no "devices" row, module or rail; an enum value is not from the lists above; a required field is missing; "combine" is missing with 2 or more devices; "feedback" does not match "positions"; "contact" is used with a "from" that cannot switch; a safety device appears in "feeds" or "mechanisms". Check also: - every channel of every I/O block has a "points" row, used or spare; - every row has "at"; - nothing in the file comes from your general knowledge of similar machines: only from these documents. Then tell me in a few lines: how many rows per table, which sheets you could not read well, and which rows you marked "uncertain". If LK On later answers with a message about the file, I will paste it here; fix exactly those rows.