Skip to content

A simple API designed to build and parse Allen Bradley *.L5X* files to empower users to automate PLC code generation.

License

Notifications You must be signed in to change notification settings

cmseaton42/L5XJS

L5XJS Logo

npm Gitter license

L5XJS

A modern TypeScript library for building and parsing Allen Bradley .L5X files to automate PLC code generation.

🚀 Version 2.0 - Now with TypeScript!

This major release brings full TypeScript support, modern ES2020 syntax, improved type safety, and a cleaner API.

Prerequisites

  • Node.js 18+ or 20+
  • TypeScript 5.0+ (for development)

Installation

npm install l5x-js

Quick Start

import { Document, Tag, Member } from 'l5x-js';

// Create a new L5X document
const doc = new Document();

// Create tags
const boolTag = new Tag({
  name: 'StartButton',
  datatype: 'BOOL',
  description: 'Start button input'
});

const intTag = new Tag({
  name: 'Counter',
  datatype: 'DINT',
  description: 'Production counter'
});

// Add tags to document
doc.addTag(boolTag);
doc.addTag(intTag);

// Generate L5X XML
console.log(doc.toString());

Advanced Example: Excel to L5X Automation

This example demonstrates how to read tag data from an Excel file and automatically generate PLC ladder logic rungs. This is particularly useful for converting alarm lists, I/O schedules, or tag databases into PLC code.

import { Document, Program, Routine, Rung } from 'l5x-js';
import * as xlsx from 'xlsx';

// Define configuration constants
const WORKSHEET_NAME = 'IO_Schedule';
const ROUTINE_NAME = 'AutoGeneratedLogic';

// Read Excel file containing tag definitions
const workbook = xlsx.readFile('./Tags.xlsm');
const worksheet = workbook.Sheets[WORKSHEET_NAME];
const tagData = xlsx.utils.sheet_to_json(worksheet);

// Initialize L5X document structure
const doc = new Document();
const program = new Program({ name: 'MainProgram' });
const routine = new Routine({ name: ROUTINE_NAME });

// Build the hierarchy: Document -> Program -> Routine
program.addRoutine(routine);
doc.addProgram(program);

// Generate ladder logic rungs from Excel data
for (const row of tagData) {
  const tagName = row['Tag'] as string;
  const isInput = row['Input/Output'] === 'Input';
  
  // Create ladder logic based on I/O type:
  // Input:  |---||---------(tagName)---|  (XIC -> OTE)
  // Output: |----|tagName|-------()----|  (XIC -> OTE)
  const rungContent = isInput 
    ? `XIC()OTE(${tagName});`           // Examine if closed, output energize
    : `XIC(${tagName})OTE();`;          // Examine if closed, output energize
  
  // Create and add rung to routine
  const rung = new Rung({ logic: rungContent });
  routine.addRung(rung);
}

// Set import target for Rockwell software
doc.setTarget(routine);

// Export L5X file ready for Studio 5000 import
doc.export(`./${WORKSHEET_NAME}_Generated.L5X`);

console.log(`Generated ${tagData.length} rungs in ${ROUTINE_NAME}`);

What This Example Does:

  1. Reads Excel Data: Imports tag information from an Excel spreadsheet containing I/O definitions
  2. Creates PLC Structure: Builds a complete L5X document with Program and Routine containers
  3. Generates Ladder Logic: Automatically creates ladder rungs based on whether tags are inputs or outputs
  4. Exports L5X File: Produces a file ready for import into Rockwell Automation Studio 5000

Excel File Format Expected:

Tag Input/Output Description
StartButton Input Main start button
StopButton Input Emergency stop
RunningLight Output Status indicator

This automation can save hours of manual PLC programming when dealing with large I/O lists or repetitive logic patterns.

API Documentation

Document Class

The main class for creating and manipulating L5X files.

Constructor

new Document(filepath?: string)

Parameters:

  • filepath (optional): Path to existing L5X file to load

Examples:

// Create new document
const doc = new Document();

// Load existing document
const doc = new Document('./existing.L5X');

Methods

addTag(tag: Tag): void

Adds a tag to the controller.

const tag = new Tag({ name: 'MyTag', datatype: 'BOOL' });
doc.addTag(tag);
getTags(): Tag[]

Returns all tags in the document.

const tags = doc.getTags();
tags.forEach(tag => console.log(tag.name));
toString(): string

Generates the L5X XML string.

const xmlContent = doc.toString();
findOne(type: string, attributes?: object): XmlElement | null

Finds the first element of specified type.

const controller = doc.findOne('Controller');
const specificTag = doc.findOne('Tag', { Name: 'MyTag' });
findAll(type: string, attributes?: object): XmlElement[]

Finds all elements of specified type.

const allTags = doc.findAll('Tag');
const boolTags = doc.findAll('Tag', { DataType: 'BOOL' });

Tag Class

Represents PLC tags with type safety and validation.

Constructor

new Tag(options: TagOptions)

TagOptions Interface:

interface TagOptions {
  name: string;           // Tag name
  datatype: string;       // PLC data type (BOOL, DINT, REAL, etc.)
  description?: string;   // Optional description
  alias?: string;         // Optional alias reference
  safety?: boolean;       // Safety tag flag
  dimension?: number;     // Array dimension
}

Examples:

// Basic tag
const tag = new Tag({
  name: 'Motor1_Run',
  datatype: 'BOOL'
});

// Tag with all options
const tag = new Tag({
  name: 'Temperature',
  datatype: 'REAL',
  description: 'Reactor temperature in °C',
  safety: false,
  dimension: 10
});

// Alias tag
const alias = new Tag({
  name: 'START_BTN',
  datatype: 'BOOL',
  alias: 'Local:1:I.Data.0'
});

Properties

name: string (readonly)

Gets the tag name.

datatype: string (readonly)

Gets the tag data type.

description: string | undefined (readonly)

Gets the tag description.

Static Methods

Tag.isTag(obj: unknown): boolean

Type guard to check if object is a Tag instance.

if (Tag.isTag(someObject)) {
  console.log(someObject.name); // TypeScript knows it's a Tag
}

Member Class

Represents PLC tag members for structured data types.

Constructor

new Member(options: MemberOptions)

MemberOptions Interface:

interface MemberOptions {
  name: string;           // Member name
  datatype: string;       // PLC data type (BOOL, DINT, REAL, etc.)
  description?: string;   // Optional description
  hidden?: boolean;       // Hidden member flag
  target?: string;        // Target reference for BOOL/BIT types
  bitNumber?: number;     // Bit number for BOOL/BIT types
}

Examples:

// Basic member
const member = new Member({
  name: 'Status',
  datatype: 'DINT'
});

// Boolean member with target
const boolMember = new Member({
  name: 'Running',
  datatype: 'BOOL',
  target: 'StatusWord',
  bitNumber: 0
});

// Member with description
const member = new Member({
  name: 'Temperature',
  datatype: 'REAL',
  description: 'Current temperature value',
  hidden: false
});

Static Methods

Member.isMember(obj: unknown): boolean

Type guard to check if object is a Member instance.

if (Member.isMember(someObject)) {
  console.log(someObject.name); // TypeScript knows it's a Member
}

Element Class

Base class for all L5X elements with XML manipulation capabilities.

Methods

findOne(type: string, attributes?: object, ignore?: string[], searchTree?: XmlElement): XmlElement | null

Finds first matching element.

Parameters:

  • type: Element type to search for
  • attributes: Optional attribute filters
  • ignore: Array of element names to ignore
  • searchTree: Optional subtree to search in
findAll(type: string, attributes?: object, ignore?: string[], searchTree?: XmlElement): XmlElement[]

Finds all matching elements.

toString(): string

Converts element to XML string.

Utility Functions

import { Util } from 'l5x-js';

// Generate hash
const id = Util.hash('some-string');

// Validation helpers
Util.validateString(value, 'parameterName');
Util.validateObject(value, 'parameterName');

Type Definitions

The library includes comprehensive TypeScript definitions:

interface XmlElement {
  type?: string;
  name?: string;
  attributes?: Record<string, string | number | boolean>;
  elements?: XmlElement[];
  text?: string;
}

interface XmlDocument {
  declaration?: {
    attributes: {
      version: string;
      encoding: string;
      standalone?: string;
    };
  };
  elements: XmlElement[];
}

Common PLC Data Types

Type Description Example
BOOL Boolean true/false
SINT Short Integer -128 to 127
INT Integer -32,768 to 32,767
DINT Double Integer -2,147,483,648 to 2,147,483,647
REAL Floating Point 3.14159
STRING Text String "Hello World"

Error Handling

The library provides descriptive error messages with type information:

try {
  const tag = new Tag({
    name: 123, // Invalid type
    datatype: 'BOOL'
  });
} catch (error) {
  console.log(error.message); // "Tag name expected type <string> but got <number>"
}

Migration from v1.x

Breaking Changes

  1. Constructor Changes: Tag constructor now uses options object

    // v1.x
    new Tag('MyTag', 'BOOL', 'Description');
    
    // v2.x
    new Tag({ name: 'MyTag', datatype: 'BOOL', description: 'Description' });
  2. Import Changes: Now uses ES6 imports

    // v1.x
    const { Document, Tag } = require('l5x-js');
    
    // v2.x
    import { Document, Tag, Member } from 'l5x-js';
  3. TypeScript: Full type safety - invalid usage caught at compile time

Development

# Install dependencies
npm install

# Run tests
npm test

# Build for production
npm run build

# Lint code
npm run lint

Built With

Contributors

Want to contribute? Check out our Contributing Guide!

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A simple API designed to build and parse Allen Bradley *.L5X* files to empower users to automate PLC code generation.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published